def empty_run(self, sx, sy, animate=False): sources, refl_fr, trans_fr = self.set_source(sx, sy) sim = mp.Simulation(cell_size=mp.Vector3(sx, sy, self.sz), geometry=[], sources=sources, boundary_layers=self.pml_layers, k_point=self.k, resolution=self.resolution) refl = sim.add_flux(self.fcen, self.df, self.nfreq, refl_fr) trans = sim.add_flux(self.fcen, self.df, self.nfreq, trans_fr) if animate: sim.run(mp.at_beginning(mp.output_epsilon), mp.to_appended("ex", mp.at_every(0.6, mp.output_efield_z)), until_after_sources=mp.stop_when_fields_decayed(25, mp.Ey, self.pt, 1e-3)) else: sim.run(until_after_sources=mp.stop_when_fields_decayed(25, mp.Ey, self.pt, 1e-3)) # for normalization run, save flux fields data for reflection plane self.store['straight_refl_data'] = sim.get_flux_data(refl) # save incident power for transmission plane self.store['flux_freqs'] = mp.get_flux_freqs(refl) self.store['straight_tran_flux'] = mp.get_fluxes(trans) self.store['straight_refl_flux'] = mp.get_fluxes(refl)
def scat_sim(): """perform scattering simulation""" scat = meep.Simulation(cell_size=cell, boundary_layers=[pml], geometry=geometry, default_material=medium, resolution=resolution) scat.init_fields() source(scat) flux_box_absorb = meep_ext.add_flux_box(scat, fcen, df, nfreq, [0, 0, 0], monitor_size) flux_box_scat = meep_ext.add_flux_box(scat, fcen, df, nfreq, [0, 0, 0], monitor_size) scat.load_minus_flux(norm_file_ext, flux_box_scat) scat.run(until_after_sources=meep.stop_when_fields_decayed( .5 * um, decay, pt=meep.Vector3(0, 0, monitor_size[2] / 2), decay_by=1e-5)) return { 'scattering': np.array(meep.get_fluxes(flux_box_scat)), 'absorption': -np.array(meep.get_fluxes(flux_box_absorb)), 'frequency': np.array(meep.get_flux_freqs(flux_box_scat)) }
def run_with_straight_waveguide(self): self.init(no_bend=True) self.sim.run(until_after_sources=mp.stop_when_fields_decayed( 50, mp.Ez, self.pt, 1e-3)) self.sim.save_flux('refl-flux', self.refl) expected = [ (0.1, 3.65231563251e-05, 3.68932495077e-05), (0.10101010101, 5.55606718876e-05, 5.6065539588e-05), (0.10202020202, 8.38211697478e-05, 8.44909864736e-05), (0.10303030303, 0.000125411162229, 0.000126268639045), (0.10404040404, 0.000186089117531, 0.000187135303398), (0.105050505051, 0.000273848867869, 0.000275039134667), (0.106060606061, 0.000399674037745, 0.000400880269423), (0.107070707071, 0.00057849953593, 0.000579454087881), (0.108080808081, 0.000830418432986, 0.000830635406881), (0.109090909091, 0.00118217282661, 0.00118084271347), (0.110101010101, 0.00166896468348, 0.00166481944189), (0.111111111111, 0.00233661613864, 0.00232776318321), (0.112121212121, 0.00324409729096, 0.00322782257917), (0.113131313131, 0.00446642217385, 0.00443896468822), (0.114141414141, 0.0060978895019, 0.0060541922825), (0.115151515152, 0.00825561352398, 0.00818906047274), (0.116161616162, 0.0110832518495, 0.010985404883), (0.117171717172, 0.0147547920552, 0.0146151488236), (0.118181818182, 0.0194782085272, 0.0192840042241), (0.119191919192, 0.0254987474079, 0.0252348211592), ] res = list( zip(mp.get_flux_freqs(self.trans), mp.get_fluxes(self.trans), mp.get_fluxes(self.refl))) np.testing.assert_allclose(expected, res[:20])
def refl_planar(self, theta, special_kz): resolution = 100 # pixels/um dpml = 1.0 sx = 3+2*dpml sy = 1/resolution cell_size = mp.Vector3(sx,sy) pml_layers = [mp.PML(dpml,direction=mp.X)] fcen = 1.0 # source wavelength = 1 um k_point = mp.Vector3(z=math.sin(theta)).scale(fcen) sources = [mp.Source(mp.GaussianSource(fcen,fwidth=0.2*fcen), component=mp.Ez, center=mp.Vector3(-0.5*sx+dpml), size=mp.Vector3(y=sy))] sim = mp.Simulation(cell_size=cell_size, boundary_layers=pml_layers, sources=sources, k_point=k_point, special_kz=special_kz, resolution=resolution) refl_fr = mp.FluxRegion(center=mp.Vector3(-0.25*sx), size=mp.Vector3(y=sy)) refl = sim.add_flux(fcen,0,1,refl_fr) sim.run(until_after_sources=mp.stop_when_fields_decayed(50,mp.Ez,mp.Vector3(),1e-9)) empty_flux = mp.get_fluxes(refl) empty_data = sim.get_flux_data(refl) sim.reset_meep() geometry = [mp.Block(material=mp.Medium(index=3.5), size=mp.Vector3(0.5*sx,mp.inf,mp.inf), center=mp.Vector3(0.25*sx))] sim = mp.Simulation(cell_size=cell_size, boundary_layers=pml_layers, geometry=geometry, sources=sources, k_point=k_point, special_kz=special_kz, resolution=resolution) refl = sim.add_flux(fcen,0,1,refl_fr) sim.load_minus_flux_data(refl,empty_data) sim.run(until_after_sources=mp.stop_when_fields_decayed(50,mp.Ez,mp.Vector3(),1e-9)) refl_flux = mp.get_fluxes(refl) Rmeep = -refl_flux[0]/empty_flux[0] return Rmeep
def main(args): sz = 100 # size of cell in z direction fcen = 1 / 3.0 # center frequency of source df = fcen / 20.0 # frequency width of source amp = args.amp # amplitude of source k = 10**args.logk # Kerr susceptibility dpml = 1.0 # PML thickness # We'll use an explicitly 1d simulation. Setting dimensions=1 will actually # result in faster execution than just using two no-size dimensions. However, # in this case Meep requires us to use E in the x direction (and H in y), # and our one no-size dimension must be z. dimensions = 1 cell = mp.Vector3(0, 0, sz) pml_layers = mp.PML(dpml) resolution = 20 # to put the same material in all space, we can just set the default material # and pass it to the Simulation constructor default_material = mp.Medium(index=1, chi3=k) sources = mp.Source(mp.GaussianSource(fcen, fwidth=df), component=mp.Ex, center=mp.Vector3(0, 0, -0.5 * sz + dpml), amplitude=amp) # frequency range for flux calculation nfreq = 400 fmin = fcen / 2.0 fmax = fcen * 4 sim = mp.Simulation(cell_size=cell, geometry=[], sources=[sources], boundary_layers=[pml_layers], default_material=default_material, resolution=resolution, dimensions=dimensions) # trans = sim.add_flux(0.5 * (fmin + fmax), fmax - fmin, nfreq, # mp.FluxRegion(mp.Vector3(0, 0, 0.5*sz - dpml - 0.5))) trans1 = sim.add_flux( fcen, 0, 1, mp.FluxRegion(mp.Vector3(0, 0, 0.5 * sz - dpml - 0.5))) trans3 = sim.add_flux( 3 * fcen, 0, 1, mp.FluxRegion(mp.Vector3(0, 0, 0.5 * sz - dpml - 0.5))) sim.run(until_after_sources=mp.stop_when_fields_decayed( 50, mp.Ex, mp.Vector3(0, 0, 0.5 * sz - dpml - 0.5), 1e-6)) # sim.display_fluxes(trans) print("harmonics:, {}, {}, {}, {}".format(k, amp, mp.get_fluxes(trans1)[0], mp.get_fluxes(trans3)[0]))
def test_3rd_harm_1d(self): expected_harmonics = [0.01, 1.0, 221.89548712071553, 1.752960413399477] self.sim.run( until_after_sources=mp.stop_when_fields_decayed( 50, mp.Ex, mp.Vector3(0, 0, (0.5 * self.sz) - self.dpml - 0.5), 1e-6 ) ) harmonics = [self.k, self.amp, mp.get_fluxes(self.trans1)[0], mp.get_fluxes(self.trans3)[0]] np.testing.assert_allclose(expected_harmonics, harmonics)
def runSimulation(thetaDegrees): thetaRadians = np.radians(thetaDegrees) kVector = mp.Vector3(np.sin(thetaRadians), 0, np.cos(thetaRadians)).scale(minimumFrequency) simulation = mp.Simulation(cell_size=cellSize, sources=sources, resolution=resolution, boundary_layers=pmlLayers, k_point=kVector) incidentFluxMonitor = simulation.add_flux(frequency, frequencyWidth, numberFrequencies, incidentRegion) simulation.run(until_after_sources=mp.stop_when_fields_decayed( 20, mp.Ex, transmissionMonitorLocation, powerDecayTarget)) incidentFluxToSubtract = simulation.get_flux_data(incidentFluxMonitor) simulation = mp.Simulation(cell_size=cellSize, sources=sources, resolution=resolution, boundary_layers=pmlLayers, geometry=geometry, k_point=kVector) transmissionRegion = mp.FluxRegion(center=transmissionMonitorLocation) transmissionFluxMonitor = simulation.add_flux(frequency, frequencyWidth, numberFrequencies, transmissionRegion) reflectionRegion = incidentRegion reflectionFluxMonitor = simulation.add_flux(frequency, frequencyWidth, numberFrequencies, reflectionRegion) simulation.load_minus_flux_data(reflectionFluxMonitor, incidentFluxToSubtract) simulation.run(until_after_sources=mp.stop_when_fields_decayed( 20, mp.Ex, transmissionMonitorLocation, powerDecayTarget)) incidentFlux = np.array(mp.get_fluxes(incidentFluxMonitor)) transmittedFlux = np.array(mp.get_fluxes(transmissionFluxMonitor)) reflectedFlux = np.array(mp.get_fluxes(reflectionFluxMonitor)) R = np.array(-reflectedFlux / incidentFlux) T = np.array(transmittedFlux / incidentFlux) frequencies = np.array(mp.get_flux_freqs(reflectionFluxMonitor)) kx = kVector.x angles = np.arcsin(kx / frequencies) return angles, frequencies, R, T
def test_3rd_harm_1d(self): expected_harmonics = [0.01, 1.0, 221.89548712071553, 1.752960413399477] self.sim.run( until_after_sources=mp.stop_when_fields_decayed( 50, mp.Ex, mp.Vector3(0, 0, (0.5 * self.sz) - self.dpml - 0.5), 1e-6 ) ) harmonics = [self.k, self.amp, mp.get_fluxes(self.trans1)[0], mp.get_fluxes(self.trans3)[0]] tol = 3e-5 if mp.is_single_precision() else 1e-7 self.assertClose(expected_harmonics, harmonics, epsilon=tol)
def main(args): sz = 100 # size of cell in z direction fcen = 1 / 3.0 # center frequency of source df = fcen / 20.0 # frequency width of source amp = args.amp # amplitude of source k = 10**args.logk # Kerr susceptibility dpml = 1.0 # PML thickness # We'll use an explicitly 1d simulation. Setting dimensions=1 will actually # result in faster execution than just using two no-size dimensions. However, # in this case Meep requires us to use E in the x direction (and H in y), # and our one no-size dimension must be z. dimensions = 1 cell = mp.Vector3(0, 0, sz) pml_layers = mp.PML(dpml) resolution = 20 # to put the same material in all space, we can just set the default material # and pass it to the Simulation constructor default_material = mp.Medium(index=1, chi3=k) sources = mp.Source(mp.GaussianSource(fcen, fwidth=df), component=mp.Ex, center=mp.Vector3(0, 0, -0.5*sz + dpml), amplitude=amp) # frequency range for flux calculation nfreq = 400 fmin = fcen / 2.0 fmax = fcen * 4 sim = mp.Simulation(cell_size=cell, geometry=[], sources=[sources], boundary_layers=[pml_layers], default_material=default_material, resolution=resolution, dimensions=dimensions) # trans = sim.add_flux(0.5 * (fmin + fmax), fmax - fmin, nfreq, # mp.FluxRegion(mp.Vector3(0, 0, 0.5*sz - dpml - 0.5))) trans1 = sim.add_flux(fcen, 0, 1, mp.FluxRegion(mp.Vector3(0, 0, 0.5*sz - dpml - 0.5))) trans3 = sim.add_flux(3 * fcen, 0, 1, mp.FluxRegion(mp.Vector3(0, 0, 0.5*sz - dpml - 0.5))) sim.run(until_after_sources=mp.stop_when_fields_decayed( 50, mp.Ex, mp.Vector3(0, 0, 0.5*sz - dpml - 0.5), 1e-6)) # sim.display_fluxes(trans) print("harmonics:, {}, {}, {}, {}".format(k, amp, mp.get_fluxes(trans1)[0], mp.get_fluxes(trans3)[0]))
def test_ninety_degree_bend(self): # We have to run the straight waveguide version first to generate the 'refl-flux' # file that this test uses. We can't just prepend run_with_straight_waveguide # with 'test_' because execution order of unit tests isn't deterministic. self.run_with_straight_waveguide() self.sim = None self.init() self.sim.load_minus_flux('refl-flux', self.refl) self.sim.run(until_after_sources=mp.stop_when_fields_decayed( 50, mp.Ez, self.pt, 1e-3)) expected = [ (0.09999999999999999, 1.8392235204829767e-5, -7.259467687598002e-6), (0.10101010101010101, 2.7629932558236724e-5, -1.1107162110079347e-5), (0.10202020202020202, 4.1001228946782745e-5, -1.687561915798036e-5), (0.10303030303030304, 6.018966076122556e-5, -2.5425779493709066e-5), (0.10404040404040406, 8.758554071933231e-5, -3.794958119189475e-5), (0.10505050505050507, 1.2656696778129198e-4, -5.612512808928115e-5), (0.10606060606060609, 1.817948859871414e-4, -8.232188174309142e-5), (0.10707070707070711, 2.594514094902856e-4, -1.1981531280672989e-4), (0.10808080808080812, 3.6736164837695035e-4, -1.7300125173897737e-4), (0.10909090909090914, 5.150131339048232e-4, -2.476730940385436e-4), (0.11010101010101016, 7.136181099374187e-4, -3.5145561406042276e-4), (0.11111111111111117, 9.76491765781944e-4, -4.944142331545938e-4), (0.11212121212121219, 0.001320033637882244, -6.897357105189368e-4), (0.11313131313131321, 0.0017653940714397098, -9.543556354451615e-4), (0.11414141414141422, 0.0023404727796352857, -0.0013095604571818236), (0.11515151515151524, 0.0030813962415392098, -0.00178176942635486), (0.11616161616161626, 0.00403238648982478, -0.0024036650652026112), (0.11717171717171727, 0.005243320443599316, -0.003215529845495731), (0.11818181818181829, 0.0067654019326068, -0.004266367104375331), (0.11919191919191931, 0.008646855439680507, -0.005614491919262783), ] res = list( zip(mp.get_flux_freqs(self.trans), mp.get_fluxes(self.trans), mp.get_fluxes(self.refl))) np.testing.assert_allclose(expected, res[:20])
def test_3rd_harm_1d(self): expected_harmonics = [0.01, 1.0, 221.89548712071553, 1.752960413399477] self.sim.run(until_after_sources=mp.stop_when_fields_decayed( 50, mp.Ex, mp.Vector3(0, 0, (0.5 * self.sz) - self.dpml - 0.5), 1e-6)) harmonics = [ self.k, self.amp, mp.get_fluxes(self.trans1)[0], mp.get_fluxes(self.trans3)[0] ] np.testing.assert_allclose(expected_harmonics, harmonics)
def norm_sim(): """perform normalization simulation""" norm = meep.Simulation(cell_size=cell, boundary_layers=[pml], geometry=[], default_material=medium, resolution=resolution) norm.init_fields() source(norm) flux_box_inc = meep_ext.add_flux_box(norm, fcen, df, nfreq, [0, 0, 0], monitor_size) flux_inc = meep_ext.add_flux_plane(norm, fcen, df, nfreq, [0, 0, 0], [box[0], box[1], 0]) norm.run(until_after_sources=meep.stop_when_fields_decayed( .5 * um, decay, pt=meep.Vector3(0, 0, monitor_size[2] / 2), decay_by=1e-3)) norm.save_flux(norm_file_ext, flux_box_inc) return { 'frequency': np.array(meep.get_flux_freqs(flux_inc)), 'area': box[0] * box[1], 'incident': np.asarray(meep.get_fluxes(flux_inc)) }
def _stop(sim): if sim.round_time() <= dt + closure['t0']: return False else: previous_fields = closure['previous_fields'] # Pull all the relevant frequency and spatial dft points relative_change = [] current_fields = [[0 for di in d] for d in dims] for mi, m in enumerate(mon): for ic, cc in enumerate(c): if isinstance(m,mp.DftFlux): current_fields[mi][ic] = mp.get_fluxes(m)[fcen_idx] elif isinstance(m,mp.DftFields): current_fields[mi][ic] = atleast_3d(sim.get_dft_array(m, cc, fcen_idx)) else: raise TypeError("Monitor of type {} not supported".format(type(m))) relative_change_raw = np.abs(previous_fields[mi][ic] - current_fields[mi][ic]) / np.abs(previous_fields[mi][ic]) relative_change.append(np.mean(relative_change_raw.flatten())) # average across space and frequency relative_change = np.mean(relative_change) # average across monitors closure['previous_fields'] = current_fields closure['t0'] = sim.round_time() if mp.verbosity > 0: fmt = "DFT decay(t = {0:1.1f}): {1:0.4e}" print(fmt.format(sim.meep_time(), np.real(relative_change))) return relative_change <= decay_by and sim.round_time() >= minimum_run_time
def norm_sim(monitor_size, unique_id): """perform normalization simulation with a given box size""" monitor_size = np.asarray(monitor_size) cell_size = monitor_size + 2 * pml_monitor_gap + 2 * pml.thickness cell = meep.Vector3(*cell_size) norm = meep.Simulation(cell_size=cell, boundary_layers=[pml], geometry=[], resolution=resolution) norm.init_fields() source(norm) flux_inc = meep_ext.add_flux_plane(norm, fcen, 0, 1, [0, 0, 0], [2 * radius, 2 * radius, 0]) flux_box_inc = meep_ext.add_flux_box(norm, fcen, 0, 1, [0, 0, 0], monitor_size) norm.run(until_after_sources=meep.stop_when_fields_decayed( .5 * um, meep.Ex, pt=meep.Vector3(0, 0, monitor_size[2] / 2), decay_by=1e-3)) norm.save_flux(norm_file_ext.format(unique_id), flux_box_inc) return { 'area': (2 * radius)**2, 'norm': np.asarray(meep.get_fluxes(flux_inc)) }
def test_dft_energy(self): resolution = 20 cell = mp.Vector3(10, 5) geom = [mp.Block(size=mp.Vector3(mp.inf, 1, mp.inf), material=mp.Medium(epsilon=12))] pml = [mp.PML(1)] fsrc = 0.15 sources = [mp.EigenModeSource(src=mp.GaussianSource(frequency=fsrc, fwidth=0.2*fsrc), center=mp.Vector3(-3), size=mp.Vector3(y=5), eig_band=1, eig_parity=mp.ODD_Z+mp.EVEN_Y, eig_match_freq=True)] sim = mp.Simulation(resolution=resolution, cell_size=cell, geometry=geom, boundary_layers=pml, sources=sources, symmetries=[mp.Mirror(direction=mp.Y)]) flux = sim.add_flux(fsrc, 0, 1, mp.FluxRegion(center=mp.Vector3(3), size=mp.Vector3(y=5))) energy = sim.add_energy(fsrc, 0, 1, mp.EnergyRegion(center=mp.Vector3(3), size=mp.Vector3(y=5))) sim.run(until_after_sources=100) res = sim.get_eigenmode_coefficients(flux, [1], eig_parity=mp.ODD_Z+mp.EVEN_Y) mode_vg = res.vgrp[0] poynting_flux = mp.get_fluxes(flux)[0] e_energy = mp.get_electric_energy(energy)[0] ratio_vg = (0.5 * poynting_flux) / e_energy m_energy = mp.get_magnetic_energy(energy)[0] t_energy = mp.get_total_energy(energy)[0] self.assertAlmostEqual(m_energy + e_energy, t_energy) self.assertAlmostEqual(ratio_vg, mode_vg, places=3)
def sim(separation, monitor_size, unique_id): """perform scattering simulation""" monitor_size = np.asarray(monitor_size) cell_size = monitor_size + 2*pml_monitor_gap + 2*pml.thickness cell = meep.Vector3(*cell_size) p1 = meep.Vector3(-separation/2, 0, 0) p2 = meep.Vector3(separation/2, 0, 0) geometry = [meep.Sphere(center=p1, radius=radius, material=gold), meep.Sphere(center=p2, radius=radius, material=gold)] scat = meep.Simulation(cell_size=cell, boundary_layers=[pml], geometry=geometry, default_material=medium, resolution=resolution) scat.init_fields() source(scat) flux_box_absorb = meep_ext.add_flux_box(scat, fcen, 0, 1, [0,0,0], monitor_size) flux_box_scat = meep_ext.add_flux_box(scat, fcen, 0, 1, [0,0,0], monitor_size) scat.load_minus_flux(norm_file_ext.format(unique_id), flux_box_scat) # scat.run(until_after_sources=8*um) scat.run(until_after_sources=meep.stop_when_fields_decayed(.5*um, polarization, pt=p2 - meep.Vector3(0,0,monitor_size[2]/2), decay_by=1e-4)) return {'scattering': np.array(meep.get_fluxes(flux_box_scat)), 'absorption': -np.array(meep.get_fluxes(flux_box_absorb))}
def compute_flux(m, n): if m == 2: sources = [ mp.Source(mp.GaussianSource(fcen, fwidth=df), component=mp.Ez, center=mp.Vector3(sx * (-0.5 + n / ndipole), -0.5 * sy + dAg + 0.5 * dsub)) ] else: sources = [ mp.Source(mp.GaussianSource(fcen, fwidth=df), component=mp.Ez, center=mp.Vector3(0, -0.5 * sy + dAg + 0.5 * dsub), size=mp.Vector3(sx, 0), amp_func=src_amp_func(n)) ] sim = mp.Simulation(cell_size=cell_size, resolution=resolution, k_point=mp.Vector3(), boundary_layers=pml_layers, geometry=geometry, sources=sources) flux_mon = sim.add_flux( fcen, df, nfreq, mp.FluxRegion(center=mp.Vector3(0, 0.5 * sy - dpml), size=mp.Vector3(sx))) sim.run(until=run_time) flux = mp.get_fluxes(flux_mon) freqs = mp.get_flux_freqs(flux_mon) return freqs, flux
def test_eigsrc_kz(self, kz_2d): resolution = 30 # pixels/um cell_size = mp.Vector3(14, 14) pml_layers = [mp.PML(thickness=2)] geometry = [ mp.Block(center=mp.Vector3(), size=mp.Vector3(mp.inf, 1, mp.inf), material=mp.Medium(epsilon=12)) ] fsrc = 0.3 # frequency of eigenmode or constant-amplitude source bnum = 1 # band number of eigenmode kz = 0.2 # fixed out-of-plane wavevector component sources = [ mp.EigenModeSource(src=mp.GaussianSource(fsrc, fwidth=0.2 * fsrc), center=mp.Vector3(), size=mp.Vector3(y=14), eig_band=bnum, eig_parity=mp.EVEN_Y, eig_match_freq=True) ] sim = mp.Simulation(cell_size=cell_size, resolution=resolution, boundary_layers=pml_layers, sources=sources, geometry=geometry, symmetries=[mp.Mirror(mp.Y)], k_point=mp.Vector3(z=kz), kz_2d=kz_2d) tran = sim.add_flux( fsrc, 0, 1, mp.FluxRegion(center=mp.Vector3(x=5), size=mp.Vector3(y=14))) sim.run(until_after_sources=50) res = sim.get_eigenmode_coefficients(tran, [1, 2], eig_parity=mp.EVEN_Y) total_flux = mp.get_fluxes(tran)[0] mode1_flux = abs(res.alpha[0, 0, 0])**2 mode2_flux = abs(res.alpha[1, 0, 0])**2 mode1_frac = 0.99 self.assertGreater(mode1_flux / total_flux, mode1_frac) self.assertLess(mode2_flux / total_flux, 1 - mode1_frac) d = 3.5 ez1 = sim.get_field_point(mp.Ez, mp.Vector3(2.3, -5.7, 4.8)) ez2 = sim.get_field_point(mp.Ez, mp.Vector3(2.3, -5.7, 4.8 + d)) ratio_ez = ez2 / ez1 phase_diff = cmath.exp(1j * 2 * cmath.pi * kz * d) self.assertAlmostEqual(ratio_ez.real, phase_diff.real, places=10) self.assertAlmostEqual(ratio_ez.imag, phase_diff.imag, places=10)
def test_waveguide_flux(self): cell_size = mp.Vector3(10, 10, 0) pml_layers = [mp.PML(thickness=2.0)] rot_angles = range( 0, 60, 20) # rotation angle of waveguide, CCW around z-axis fluxes = [] for t in rot_angles: rot_angle = math.radians(t) sources = [ mp.EigenModeSource(src=mp.GaussianSource(1.0, fwidth=0.1), size=mp.Vector3(y=10), center=mp.Vector3(x=-3), direction=mp.NO_DIRECTION, eig_kpoint=mp.Vector3( math.cos(rot_angle), math.sin(rot_angle), 0), eig_band=1, eig_parity=mp.ODD_Z, eig_match_freq=True) ] geometry = [ mp.Block(center=mp.Vector3(), size=mp.Vector3(mp.inf, 1, mp.inf), e1=mp.Vector3(1, 0, 0).rotate(mp.Vector3(0, 0, 1), rot_angle), e2=mp.Vector3(0, 1, 0).rotate(mp.Vector3(0, 0, 1), rot_angle), material=mp.Medium(index=1.5)) ] sim = mp.Simulation(cell_size=cell_size, resolution=50, boundary_layers=pml_layers, sources=sources, geometry=geometry) tran = sim.add_flux( 1.0, 0, 1, mp.FluxRegion(center=mp.Vector3(x=3), size=mp.Vector3(y=10))) sim.run(until_after_sources=100) fluxes.append(mp.get_fluxes(tran)[0]) print("flux:, {:.2f}, {:.6f}".format(t, fluxes[-1])) self.assertAlmostEqual(fluxes[0], fluxes[1], places=0) self.assertAlmostEqual(fluxes[1], fluxes[2], places=0) # self.assertAlmostEqual(fluxes[0], fluxes[2], places=0) # sadly the above line requires a workaround due to the # following annoying numerical accident: # AssertionError: 100.33815231783535 != 99.81145343586365 within 0 places f0, f2 = fluxes[0], fluxes[2] self.assertLess(abs(f0 - f2), 0.5 * max(abs(f0), abs(f2)))
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 plot_power(self): flux_freqs = np.array(mp.get_flux_freqs(self.box_z2)) flux_up = np.array(mp.get_fluxes(self.box_z2)) flux_bot = np.array(mp.get_fluxes(self.box_z1)) flux_side = np.array(mp.get_fluxes(self.box_r)) flux_total = flux_bot + flux_up + flux_side flux_wvl = 1 / flux_freqs plt.figure(dpi=150) plt.plot(flux_wvl, flux_total, 'r-', label='Total emission') plt.plot(flux_wvl, flux_bot, 'g-', label='Bottom emission') plt.plot(flux_wvl, flux_side, 'y-', label='Side emission') plt.plot(flux_wvl, flux_up, 'b-', label='Upward emission') plt.legend(loc='upper right') plt.xlabel('Wavelength (µm)') plt.ylabel('Arbitrary intensity') return flux_freqs, flux_up, flux_bot, flux_side
def my_display_fluxes(sim): nonlocal my_display_count nonlocal step_time freqs=mp.get_flux_freqs(trans[0]) fluxes=[mp.get_fluxes(tran) for tran in trans] data=np.column_stack((freqs, *fluxes,)) my.matrix_output(None,data,"{:10.3e}","flux") my_display_count+=1 print('No. {} display at t={}'.format( my_display_count,step_time)) mymeep.my_flush_step(sim)
def grating(gp,gh,gdc,oddz): sx = dpml+dsub+gh+dpad+dpml sy = gp cell_size = mp.Vector3(sx,sy,0) pml_layers = [mp.PML(thickness=dpml,direction=mp.X)] src_pt = mp.Vector3(-0.5*sx+dpml+0.5*dsub,0,0) sources = [mp.Source(mp.GaussianSource(fcen, fwidth=df), component=mp.Ez if oddz else mp.Hz, center=src_pt, size=mp.Vector3(0,sy,0))] symmetries=[mp.Mirror(mp.Y, phase=+1 if oddz else -1)] sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=pml_layers, k_point=k_point, default_material=glass, sources=sources, symmetries=symmetries) mon_pt = mp.Vector3(0.5*sx-dpml-0.5*dpad,0,0) flux_mon = sim.add_flux(fcen, df, nfreq, mp.FluxRegion(center=mon_pt, size=mp.Vector3(0,sy,0))) sim.run(until_after_sources=100) input_flux = mp.get_fluxes(flux_mon) 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=pml_layers, geometry=geometry, k_point=k_point, sources=sources, symmetries=symmetries) mode_mon = sim.add_flux(fcen, df, nfreq, mp.FluxRegion(center=mon_pt, size=mp.Vector3(0,sy,0))) sim.run(until_after_sources=300) freqs = mp.get_eigenmode_freqs(mode_mon) res = sim.get_eigenmode_coefficients(mode_mon, [1], eig_parity=mp.ODD_Z+mp.EVEN_Y if oddz else mp.EVEN_Z+mp.ODD_Y) coeffs = res.alpha mode_wvl = [1/freqs[nf] for nf in range(nfreq)] mode_tran = [abs(coeffs[0,nf,0])**2/input_flux[nf] for nf in range(nfreq)] mode_phase = [np.angle(coeffs[0,nf,0]) for nf in range(nfreq)] return mode_wvl, mode_tran, mode_phase
def test_divide_parallel_processes(self): resolution = 20 sxy = 4 dpml = 1 cell = mp.Vector3(sxy + 2 * dpml, sxy + 2 * dpml) pml_layers = [mp.PML(dpml)] n = mp.divide_parallel_processes(2) fcen = 1.0 / (n + 1) sources = [ mp.Source(src=mp.GaussianSource(fcen, fwidth=0.2 * fcen), center=mp.Vector3(), component=mp.Ez) ] symmetries = [mp.Mirror(mp.X), mp.Mirror(mp.Y)] self.sim = mp.Simulation(cell_size=cell, resolution=resolution, sources=sources, symmetries=symmetries, boundary_layers=pml_layers) flux_box = self.sim.add_flux(fcen, 0, 1, mp.FluxRegion(mp.Vector3(y=0.5 * sxy), size=mp.Vector3(sxy)), mp.FluxRegion(mp.Vector3(y=-0.5 * sxy), size=mp.Vector3(sxy), weight=-1), mp.FluxRegion(mp.Vector3(0.5 * sxy), size=mp.Vector3(y=sxy)), mp.FluxRegion(mp.Vector3(-0.5 * sxy), size=mp.Vector3(y=sxy), weight=-1), decimation_factor=1) self.sim.run(until_after_sources=30) tot_flux = mp.get_fluxes(flux_box)[0] tot_fluxes = mp.merge_subgroup_data(tot_flux) fcens = mp.merge_subgroup_data(fcen) self.assertEqual(fcens[0], 1) self.assertEqual(fcens[1], 0.5) places = 4 if mp.is_single_precision() else 7 self.assertAlmostEqual(tot_fluxes[0], 9.8628728533, places=places) self.assertAlmostEqual(tot_fluxes[1], 19.6537275387, places=places)
def test_chunks(self): sxy = 10 cell = mp.Vector3(sxy, sxy, 0) fcen = 1.0 # pulse center frequency df = 0.1 # pulse width (in frequency) sources = [mp.Source(mp.GaussianSource(fcen, fwidth=df), mp.Ez, mp.Vector3())] dpml = 1.0 pml_layers = [mp.PML(dpml)] resolution = 10 sim = mp.Simulation(cell_size=cell, boundary_layers=pml_layers, sources=sources, resolution=resolution, split_chunks_evenly=False) sim.use_output_directory(temp_dir) top = mp.FluxRegion(center=mp.Vector3(0,+0.5*sxy-dpml), size=mp.Vector3(sxy-2*dpml,0), weight=+1.0) bot = mp.FluxRegion(center=mp.Vector3(0,-0.5*sxy+dpml), size=mp.Vector3(sxy-2*dpml,0), weight=-1.0) rgt = mp.FluxRegion(center=mp.Vector3(+0.5*sxy-dpml,0), size=mp.Vector3(0,sxy-2*dpml), weight=+1.0) lft = mp.FluxRegion(center=mp.Vector3(-0.5*sxy+dpml,0), size=mp.Vector3(0,sxy-2*dpml), weight=-1.0) tot_flux = sim.add_flux(fcen, 0, 1, top, bot, rgt, lft) sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, mp.Vector3(), 1e-5)) sim.save_flux('tot_flux', tot_flux) sim1 = sim geometry = [mp.Block(center=mp.Vector3(), size=mp.Vector3(sxy, sxy, mp.inf), material=mp.Medium(index=3.5)), mp.Block(center=mp.Vector3(), size=mp.Vector3(sxy-2*dpml, sxy-2*dpml, mp.inf), material=mp.air)] sim = mp.Simulation(cell_size=cell, geometry=geometry, boundary_layers=pml_layers, sources=sources, resolution=resolution, chunk_layout=sim1) sim.use_output_directory(temp_dir) tot_flux = sim.add_flux(fcen, 0, 1, top, bot, rgt, lft) sim.load_minus_flux('tot_flux', tot_flux) sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, mp.Vector3(), 1e-5)) self.assertAlmostEqual(86.90826609300862, mp.get_fluxes(tot_flux)[0])
def disk_run(self, sx, sy): sources, refl_fr, trans_fr = self.set_source(sx, sy) sim = mp.Simulation(cell_size=mp.Vector3(sx, sy, self.sz), geometry=self.geometry, sources=sources, boundary_layers=self.pml_layers, k_point=self.k, resolution=self.resolution) refl = sim.add_flux(self.fcen, self.df, self.nfreq, refl_fr) trans = sim.add_flux(self.fcen, self.df, self.nfreq, trans_fr) # for normal run, load negated fields to subtract incident from refl. fields sim.load_minus_flux_data(refl, self.store['straight_refl_data']) sim.run(until_after_sources=mp.stop_when_fields_decayed(25, mp.Ey, self.pt, 1e-3)) self.store['disk_refl_flux'] = mp.get_fluxes(refl) self.store['disk_tran_flux'] = mp.get_fluxes(trans)
def simulation(sim, cell, det_dir, det_tran, det_tran_2, **simrun_args): #inicialitzo els dos detectors (a les diferents posicions) det_dir = det_dir #Detectors(center=mp.Vector3(-4.25,0,0),size=mp.Vector3(0,5.0,0)) det_tran = det_tran #Detectors(center=mp.Vector3(3.25,0,0),size=mp.Vector3(0,5.0,0)) det_tran_2 = det_tran_2 #afegeixo els fluxos direct = sim.add_flux(Wave.fcen, Wave.df, Wave.nfreq, det_dir.detect_fr) tran = sim.add_flux(Wave.fcen, Wave.df, Wave.nfreq, det_tran.detect_fr) tran_2 = sim.add_flux(Wave.fcen, Wave.df, Wave.nfreq, det_tran_2.detect_fr) sim.run(**simrun_args) #prenc les dades per fer els dibuixos eps_data = sim.get_array(center=mp.Vector3(), size=cell, component=mp.Dielectric) ez_data = sim.get_array(center=mp.Vector3(), size=cell, component=mp.Ez) #prenc les dades per fer les gràfiques flux_freqs = mp.get_flux_freqs(direct) direct_data = mp.get_fluxes(direct) tran_data = mp.get_fluxes(tran) tran_data_2 = mp.get_fluxes(tran_2) reset = sim.reset_meep() return eps_data, ez_data, flux_freqs, direct_data, tran_data, tran_data_2, reset
def run_chi3(k_pow, amp=1): k = 10**k_pow default_material = mp.Medium(index=1, chi3=k) sources = mp.Source(mp.GaussianSource(fcen, fwidth=df), component=mp.Ex, center=mp.Vector3(0, 0, -0.5 * sz + dpml), amplitude=amp) sim = mp.Simulation(cell_size=cell, geometry=[], sources=[sources], boundary_layers=[pml_layers], default_material=default_material, resolution=resolution, dimensions=dimensions) trans = sim.add_flux( 0.5 * (fmin + fmax), fmax - fmin, nfreq, mp.FluxRegion(mp.Vector3(0, 0, 0.5 * sz - dpml - 0.5))) # Single frequency point at omega trans1 = sim.add_flux( fcen, 0, 1, mp.FluxRegion(mp.Vector3(0, 0, 0.5 * sz - dpml - 0.5))) # Singel frequency point at 3omega trans3 = sim.add_flux( 3 * fcen, 0, 1, mp.FluxRegion(mp.Vector3(0, 0, 0.5 * sz - dpml - 0.5))) sim.run(until_after_sources=mp.stop_when_fields_decayed( 50, mp.Ex, mp.Vector3(0, 0, 0.5 * sz - dpml - 0.5), 1e-6)) omega_flux = mp.get_fluxes(trans1) omega3_flux = mp.get_fluxes(trans3) freqs = mp.get_flux_freqs(trans) spectra = mp.get_fluxes(trans) return freqs, spectra, omega_flux, omega3_flux
def run_power(self, time_after_sources=100): self.time_after_sources = time_after_sources self._sim.run(until_after_sources=self.time_after_sources) flux_freqs = np.array(mp.get_flux_freqs(self.box_z2)) flux_up = np.array(mp.get_fluxes(self.box_z2)) flux_bot = np.array(mp.get_fluxes(self.box_z1)) flux_side = np.array(mp.get_fluxes(self.box_r)) flux_total = flux_bot + flux_up + flux_side max_uppower = max(flux_up) max_totalpower = max(flux_total) max_upindex = np.where(flux_up == max_uppower) maxwvl = 1 / flux_freqs[max_upindex] # find the wavelength of maximum sum_upratio = sum(flux_up) / sum( flux_total) # the ratio of total upward power max_upratio = max(flux_up) / max( flux_total ) # at the most productive wavelength, thr ratio of upward power flux_wvl = 1 / flux_freqs plt.figure(dpi=150) plt.axvline(x=maxwvl, color='b', linestyle='--') # mark where moset productive wavelength plt.plot(flux_wvl, flux_total, 'r-', label='Total emission') plt.plot(flux_wvl, flux_bot, 'g-', label='Bottom emission') plt.plot(flux_wvl, flux_side, 'y-', label='Side emission') plt.plot(flux_wvl, flux_up, 'b-', label='Upward emission') plt.legend(loc='upper right') plt.xlabel('Wavelength (µm)') plt.ylabel('Arbitrary intensity') return flux_freqs, flux_up, flux_bot, flux_side
def test_chunks(self): sxy = 10 cell = mp.Vector3(sxy, sxy, 0) fcen = 1.0 # pulse center frequency df = 0.1 # pulse width (in frequency) sources = [mp.Source(mp.GaussianSource(fcen, fwidth=df), mp.Ez, mp.Vector3())] dpml = 1.0 pml_layers = [mp.PML(dpml)] resolution = 10 sim = mp.Simulation(cell_size=cell, boundary_layers=pml_layers, sources=sources, resolution=resolution, split_chunks_evenly=False) top = mp.FluxRegion(center=mp.Vector3(0,+0.5*sxy-dpml), size=mp.Vector3(sxy-2*dpml,0), weight=+1.0) bot = mp.FluxRegion(center=mp.Vector3(0,-0.5*sxy+dpml), size=mp.Vector3(sxy-2*dpml,0), weight=-1.0) rgt = mp.FluxRegion(center=mp.Vector3(+0.5*sxy-dpml,0), size=mp.Vector3(0,sxy-2*dpml), weight=+1.0) lft = mp.FluxRegion(center=mp.Vector3(-0.5*sxy+dpml,0), size=mp.Vector3(0,sxy-2*dpml), weight=-1.0) tot_flux = sim.add_flux(fcen, 0, 1, top, bot, rgt, lft) sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, mp.Vector3(), 1e-5)) sim.save_flux('tot_flux', tot_flux) sim1 = sim geometry = [mp.Block(center=mp.Vector3(), size=mp.Vector3(sxy, sxy, mp.inf), material=mp.Medium(index=3.5)), mp.Block(center=mp.Vector3(), size=mp.Vector3(sxy-2*dpml, sxy-2*dpml, mp.inf), material=mp.air)] sim = mp.Simulation(cell_size=cell, geometry=geometry, boundary_layers=pml_layers, sources=sources, resolution=resolution, chunk_layout=sim1) tot_flux = sim.add_flux(fcen, 0, 1, top, bot, rgt, lft) sim.load_minus_flux('tot_flux', tot_flux) sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, mp.Vector3(), 1e-5)) self.assertAlmostEqual(86.90826609300862, mp.get_fluxes(tot_flux)[0])
def force_norm(): """perform normalization simulation""" norm = meep.Simulation(cell_size=cell, boundary_layers=[pml], geometry=[], resolution=resolution) norm.init_fields() source(norm) flux_inc = meep_ext.add_flux_plane(norm, fcen, df, nfreq, [0,0,0], [2*radius, 2*radius, 0]) norm.run(until_after_sources=meep.stop_when_fields_decayed(.5*um, decay, pt=meep.Vector3(0,0,0), decay_by=1e-5)) return {'frequency': np.array(meep.get_flux_freqs(flux_inc)), 'area': (2*radius)**2, 'incident': np.asarray(meep.get_fluxes(flux_inc))}
def test_waveguide_flux(self): cell_size = mp.Vector3(10,10,0) pml_layers = [mp.PML(thickness=2.0)] rot_angles = range(0,60,20) # rotation angle of waveguide, CCW around z-axis fluxes = [] for t in rot_angles: rot_angle = math.radians(t) sources = [mp.EigenModeSource(src=mp.GaussianSource(1.0,fwidth=0.1), size=mp.Vector3(y=10), center=mp.Vector3(x=-3), direction=mp.NO_DIRECTION, eig_kpoint=mp.Vector3(math.cos(rot_angle),math.sin(rot_angle),0), eig_band=1, eig_parity=mp.ODD_Z, eig_match_freq=True)] geometry = [mp.Block(center=mp.Vector3(), size=mp.Vector3(mp.inf,1,mp.inf), e1 = mp.Vector3(1,0,0).rotate(mp.Vector3(0,0,1), rot_angle), e2 = mp.Vector3(0,1,0).rotate(mp.Vector3(0,0,1), rot_angle), material=mp.Medium(index=1.5))] sim = mp.Simulation(cell_size=cell_size, resolution=50, boundary_layers=pml_layers, sources=sources, geometry=geometry) tran = sim.add_flux(1.0, 0, 1, mp.FluxRegion(center=mp.Vector3(x=3), size=mp.Vector3(y=10))) sim.run(until_after_sources=100) fluxes.append(mp.get_fluxes(tran)[0]) print("flux:, {:.2f}, {:.6f}".format(t,fluxes[-1])) self.assertAlmostEqual(fluxes[0], fluxes[1], places=0) self.assertAlmostEqual(fluxes[1], fluxes[2], places=0) # self.assertAlmostEqual(fluxes[0], fluxes[2], places=0) # sadly the above line requires a workaround due to the # following annoying numerical accident: # AssertionError: 100.33815231783535 != 99.81145343586365 within 0 places f0,f2=fluxes[0],fluxes[2] self.assertLess( abs(f0-f2), 0.5*max(abs(f0),abs(f2)) )
def norm_sim(): """perform normalization simulation""" L = 2*radius + 2*pml_monitor_gap + 2*particle_monitor_gap + 2*pml.thickness cell = meep.Vector3(L,L,L) norm = meep.Simulation(cell_size=cell, boundary_layers=[pml], geometry=[], resolution=resolution) norm.init_fields() source(norm) flux_inc = meep_ext.add_flux_plane(norm, fcen, 0, 1, [0,0,0], [2*radius, 2*radius, 0]) norm.run(until_after_sources=meep.stop_when_fields_decayed(.5*um, meep.Ex, pt=meep.Vector3(0,0,0), decay_by=1e-3)) return {'area': (2*radius)**2, 'norm': np.asarray(meep.get_fluxes(flux_inc))}
def test_dft_energy(self): resolution = 20 cell = mp.Vector3(10, 5) geom = [ mp.Block(size=mp.Vector3(mp.inf, 1, mp.inf), material=mp.Medium(epsilon=12)) ] pml = [mp.PML(1)] fsrc = 0.15 sources = [ mp.EigenModeSource(src=mp.GaussianSource(frequency=fsrc, fwidth=0.2 * fsrc), center=mp.Vector3(-3), size=mp.Vector3(y=5), eig_band=1, eig_parity=mp.ODD_Z + mp.EVEN_Y, eig_match_freq=True) ] sim = mp.Simulation(resolution=resolution, cell_size=cell, geometry=geom, boundary_layers=pml, sources=sources, symmetries=[mp.Mirror(direction=mp.Y)]) flux = sim.add_flux( fsrc, 0, 1, mp.FluxRegion(center=mp.Vector3(3), size=mp.Vector3(y=5))) energy = sim.add_energy( fsrc, 0, 1, mp.EnergyRegion(center=mp.Vector3(3), size=mp.Vector3(y=5))) sim.run(until_after_sources=100) res = sim.get_eigenmode_coefficients(flux, [1], eig_parity=mp.ODD_Z + mp.EVEN_Y) mode_vg = res.vgrp[0] poynting_flux = mp.get_fluxes(flux)[0] e_energy = mp.get_electric_energy(energy)[0] ratio_vg = (0.5 * poynting_flux) / e_energy m_energy = mp.get_magnetic_energy(energy)[0] t_energy = mp.get_total_energy(energy)[0] self.assertAlmostEqual(m_energy + e_energy, t_energy) self.assertAlmostEqual(ratio_vg, mode_vg, places=3)
def flux_monitor_cal(box_x1, box_x2, box_y1, box_y2, box_z1, box_z2): box_x1_flux = mp.get_fluxes(box_x1) box_x2_flux = mp.get_fluxes(box_x2) box_y1_flux = mp.get_fluxes(box_y1) box_y2_flux = mp.get_fluxes(box_y2) box_z1_flux = mp.get_fluxes(box_z1) box_z2_flux = mp.get_fluxes(box_z2) frqs = mp.get_flux_freqs(box_x1) p_flux = -(np.asarray(box_x1_flux) - np.asarray(box_x2_flux) + np.asarray(box_y1_flux) - np.asarray(box_y2_flux) + np.asarray(box_z1_flux) - np.asarray(box_z2_flux)) return frqs, p_flux
def test_transmission_spectrum(self): expected = [ (0.15, 7.218492264696595e-6), (0.1504008016032064, 6.445696315927592e-6), (0.1508016032064128, 5.140949243632777e-6), (0.15120240480961922, 3.6159747936427164e-6), (0.15160320641282563, 2.263940553705969e-6), (0.15200400801603203, 1.4757165844336744e-6), (0.15240480961923844, 1.5491803919142815e-6), (0.15280561122244485, 2.612053246626972e-6), (0.15320641282565126, 4.577504371188737e-6), (0.15360721442885766, 7.1459089162998185e-6), (0.15400801603206407, 9.856622013418823e-6), (0.15440881763527048, 1.2182309227954296e-5), (0.1548096192384769, 1.3647726444709649e-5), (0.1552104208416833, 1.3947420613633674e-5), (0.1556112224448897, 1.303466755716231e-5), (0.1560120240480961, 1.115807915037775e-5), (0.15641282565130252, 8.832335196969796e-6), (0.15681362725450892, 6.743645773127985e-6), (0.15721442885771533, 5.605913756087576e-6), (0.15761523046092174, 5.996668564026961e-6), (0.15801603206412815, 8.209400611614078e-6), (0.15841683366733456, 1.2158641936828497e-5), (0.15881763527054096, 1.73653230513453e-5), (0.15921843687374737, 2.303382576477893e-5), (0.15961923847695378, 2.821180350795834e-5), (0.1600200400801602, 3.200359292911769e-5), (0.1604208416833666, 3.3792624373001934e-5), (0.160821643286573, 3.342171394788991e-5), (0.1612224448897794, 3.1284866146526904e-5), (0.16162324649298582, 2.830022088581398e-5), (0.16202404809619222, 2.5758413657344014e-5), (0.16242484969939863, 2.506899997971769e-5), (0.16282565130260504, 2.7453508915303887e-5), (0.16322645290581145, 3.365089813497114e-5), (0.16362725450901786, 4.370486834112e-5), (0.16402805611222426, 5.689050715055283e-5), (0.16442885771543067, 7.181133157470506e-5), (0.16482965931863708, 8.666168027415369e-5), (0.16523046092184349, 9.961094123261317e-5), (0.1656312625250499, 1.0923388232657953e-4), (0.1660320641282563, 1.1489334204708105e-4), (0.1664328657314627, 1.1698318060032011e-4), (0.16683366733466912, 1.169621456132733e-4), (0.16723446893787552, 1.1714995241571987e-4), (0.16763527054108193, 1.2030783847222252e-4), (0.16803607214428834, 1.2907652919660887e-4), ] self.sim.sources = [ mp.Source(mp.GaussianSource(self.fcen, fwidth=self.df), mp.Ey, mp.Vector3(self.dpml + (-0.5 * self.sx)), size=mp.Vector3(0, self.w)) ] self.sim.symmetries = [mp.Mirror(mp.Y, phase=-1)] freg = mp.FluxRegion(center=mp.Vector3((0.5 * self.sx) - self.dpml - 0.5), size=mp.Vector3(0, 2 * self.w)) trans = self.sim.add_flux(self.fcen, self.df, self.nfreq, freg) self.sim.run( until_after_sources=mp.stop_when_fields_decayed( 50, mp.Ey, mp.Vector3((0.5 * self.sx) - self.dpml - 0.5, 0), 1e-1) ) res = zip(mp.get_flux_freqs(trans), mp.get_fluxes(trans)) for e, r in zip(expected, res): np.testing.assert_allclose(e, r)
nfreq = 50 sources = [ mp.Source(mp.GaussianSource(fcen,fwidth=df), component=mp.Ex, center=mp.Vector3(0,0,-0.5*sz+dpml)) ] sim = mp.Simulation(cell_size=cell_size, boundary_layers=pml_layers, sources=sources, dimensions=1, resolution=resolution) refl_fr = mp.FluxRegion(center=mp.Vector3(0,0,-0.25*sz)) refl = sim.add_flux(fcen, df, nfreq, refl_fr) sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ex, mp.Vector3(), 1e-9)) empty_flux = mp.get_fluxes(refl) empty_data = sim.get_flux_data(refl) sim.reset_meep() geometry = [ mp.Block(mp.Vector3(mp.inf,mp.inf,0.5*sz), center=mp.Vector3(0,0,0.25*sz), material=fused_quartz) ] sim = mp.Simulation(cell_size=cell_size, boundary_layers=pml_layers, geometry=geometry, sources=sources, dimensions=1, resolution=resolution) refl = sim.add_flux(fcen, df, nfreq, refl_fr) sim.load_minus_flux_data(refl, empty_data)
def parallel_waveguide(s,xodd): geometry = [mp.Block(center=mp.Vector3(-0.5*(s+a)), size=mp.Vector3(a,a,mp.inf), material=Si), mp.Block(center=mp.Vector3(0.5*(s+a)), size=mp.Vector3(a,a,mp.inf), material=Si)] symmetries = [mp.Mirror(mp.X, phase=-1.0 if xodd else 1.0), mp.Mirror(mp.Y, phase=-1.0)] sources = [mp.Source(src=mp.GaussianSource(fcen, fwidth=df), component=mp.Ey, center=mp.Vector3(-0.5*(s+a)), size=mp.Vector3(a,a)), mp.Source(src=mp.GaussianSource(fcen, fwidth=df), component=mp.Ey, center=mp.Vector3(0.5*(s+a)), size=mp.Vector3(a,a), amplitude=-1.0 if xodd else 1.0)] sim = mp.Simulation(resolution=resolution, cell_size=cell, boundary_layers=pml_layers, geometry=geometry, symmetries=symmetries, k_point=k_point, sources=sources) h = mp.Harminv(mp.Ey, mp.Vector3(0.5*(s+a)), fcen, df) sim.run(mp.after_sources(h), until_after_sources=200) f = h.modes[0].freq print("freq:, {}, {}".format(s, f)) sim.reset_meep() eig_sources = [mp.EigenModeSource(src=mp.GaussianSource(f, fwidth=df), size=mp.Vector3(a,a), center=mp.Vector3(-0.5*(s+a)), eig_kpoint=k_point, eig_match_freq=True, eig_parity=mp.ODD_Y), mp.EigenModeSource(src=mp.GaussianSource(f, fwidth=df), size=mp.Vector3(a,a), center=mp.Vector3(0.5*(s+a)), eig_kpoint=k_point, eig_match_freq=True, eig_parity=mp.ODD_Y, amplitude=-1.0 if xodd else 1.0)] sim.change_sources(eig_sources) flux_reg = mp.FluxRegion(direction=mp.Z, center=mp.Vector3(), size=mp.Vector3(1.2*(2*a+s),1.2*a)) wvg_flux = sim.add_flux(f, 0, 1, flux_reg) force_reg1 = mp.ForceRegion(mp.Vector3(0.5*s), direction=mp.X, weight=1.0, size=mp.Vector3(y=a)) force_reg2 = mp.ForceRegion(mp.Vector3(0.5*s+a), direction=mp.X, weight=-1.0, size=mp.Vector3(y=a)) wvg_force = sim.add_force(f, 0, 1, force_reg1, force_reg2) sim.run(until_after_sources=5000) flux = mp.get_fluxes(wvg_flux)[0] force = mp.get_forces(wvg_force)[0] sim.reset_meep() return flux, force
def pol_grating(d,ph,gp,nmode): sx = dpml+dsub+d+d+dpad+dpml sy = gp cell_size = mp.Vector3(sx,sy,0) # twist angle of nematic director; from equation 1b def phi(p): xx = p.x-(-0.5*sx+dpml+dsub) if (xx >= 0) and (xx <= d): return math.pi*p.y/gp + ph*xx/d else: return math.pi*p.y/gp - ph*xx/d + 2*ph # return the anisotropic permittivity tensor for a uniaxial, twisted nematic liquid crystal def lc_mat(p): # rotation matrix for rotation around x axis Rx = mp.Matrix(mp.Vector3(1,0,0),mp.Vector3(0,math.cos(phi(p)),math.sin(phi(p))),mp.Vector3(0,-math.sin(phi(p)),math.cos(phi(p)))) lc_epsilon = Rx * epsilon_diag * Rx.transpose() lc_epsilon_diag = mp.Vector3(lc_epsilon[0].x,lc_epsilon[1].y,lc_epsilon[2].z) lc_epsilon_offdiag = mp.Vector3(lc_epsilon[1].x,lc_epsilon[2].x,lc_epsilon[2].y) return mp.Medium(epsilon_diag=lc_epsilon_diag,epsilon_offdiag=lc_epsilon_offdiag) geometry = [mp.Block(center=mp.Vector3(-0.5*sx+0.5*(dpml+dsub)),size=mp.Vector3(dpml+dsub,mp.inf,mp.inf),material=mp.Medium(index=n_0)), mp.Block(center=mp.Vector3(-0.5*sx+dpml+dsub+d),size=mp.Vector3(2*d,mp.inf,mp.inf),material=lc_mat)] # linear-polarized planewave pulse source src_pt = mp.Vector3(-0.5*sx+dpml+0.3*dsub,0,0) sources = [mp.Source(mp.GaussianSource(fcen,fwidth=0.05*fcen), component=mp.Ez, center=src_pt, size=mp.Vector3(0,sy,0)), mp.Source(mp.GaussianSource(fcen,fwidth=0.05*fcen), component=mp.Ey, center=src_pt, size=mp.Vector3(0,sy,0))] sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=pml_layers, k_point=k_point, sources=sources, default_material=mp.Medium(index=n_0)) 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) input_flux = mp.get_fluxes(tran_flux) input_flux_data = sim.get_flux_data(tran_flux) sim.reset_meep() sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=pml_layers, k_point=k_point, sources=sources, geometry=geometry) tran_flux = sim.add_flux(fcen, 0, 1, mp.FluxRegion(center=tran_pt, size=mp.Vector3(0,sy,0))) sim.run(until_after_sources=300) res1 = sim.get_eigenmode_coefficients(tran_flux, range(1,nmode+1), eig_parity=mp.ODD_Z+mp.EVEN_Y) res2 = sim.get_eigenmode_coefficients(tran_flux, range(1,nmode+1), eig_parity=mp.EVEN_Z+mp.ODD_Y) angles = [math.degrees(math.acos(kdom.x/fcen)) for kdom in res1.kdom] return input_flux[0], angles, res1.alpha[:,0,0], res2.alpha[:,0,0];
sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=pml_layers, k_point=k_point, default_material=glass, sources=sources, symmetries=symmetries) nfreq = 21 mon_pt = mp.Vector3(0.5*sx-dpml-0.5*dpad,0,0) flux_mon = sim.add_flux(fcen, df, nfreq, mp.FluxRegion(center=mon_pt, size=mp.Vector3(0,sy,0))) sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, mon_pt, 1e-9)) input_flux = mp.get_fluxes(flux_mon) 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=pml_layers, geometry=geometry, k_point=k_point, sources=sources, symmetries=symmetries) mode_mon = sim.add_flux(fcen, df, nfreq, mp.FluxRegion(center=mon_pt, size=mp.Vector3(0,sy,0)))
sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=boundary_layers, geometry=[mp.Prism(vertices,height=mp.inf,material=Si)], sources=sources, symmetries=symmetries) mon_pt = mp.Vector3(-0.5*sx+dpml_x+0.7*Lw) flux = sim.add_flux(fcen,0,1,mp.FluxRegion(center=mon_pt,size=mp.Vector3(y=sy-2*dpml_y))) sim.run(until_after_sources=mp.stop_when_fields_decayed(50,mp.Ez,mon_pt,1e-9)) res = sim.get_eigenmode_coefficients(flux,[1],eig_parity=mp.ODD_Z+mp.EVEN_Y) incident_coeffs = res.alpha incident_flux = mp.get_fluxes(flux) incident_flux_data = sim.get_flux_data(flux) sim.reset_meep() # linear taper vertices = [mp.Vector3(-0.5*sx-1,0.5*w1), mp.Vector3(-0.5*Lt,0.5*w1), mp.Vector3(0.5*Lt,0.5*w2), mp.Vector3(0.5*sx+1,0.5*w2), mp.Vector3(0.5*sx+1,-0.5*w2), mp.Vector3(0.5*Lt,-0.5*w2), mp.Vector3(-0.5*Lt,-0.5*w1), mp.Vector3(-0.5*sx-1,-0.5*w1)] sim = mp.Simulation(resolution=resolution,
def test_refl_angular(self): resolution = 100 dpml = 1.0 sz = 10 sz = sz + 2 * dpml cell_size = mp.Vector3(z=sz) pml_layers = [mp.PML(dpml)] wvl_min = 0.4 wvl_max = 0.8 fmin = 1 / wvl_max fmax = 1 / wvl_min fcen = 0.5 * (fmin + fmax) df = fmax - fmin nfreq = 50 theta_r = math.radians(0) k = mp.Vector3(math.sin(theta_r), 0, math.cos(theta_r)).scale(fcen) dimensions = 1 sources = [mp.Source(mp.GaussianSource(fcen, fwidth=df), component=mp.Ex, center=mp.Vector3(z=-0.5 * sz + dpml))] sim = mp.Simulation(cell_size=cell_size, boundary_layers=pml_layers, sources=sources, k_point=k, dimensions=dimensions, resolution=resolution) refl_fr = mp.FluxRegion(center=mp.Vector3(z=-0.25 * sz)) refl = sim.add_flux(fcen, df, nfreq, refl_fr) sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ex, mp.Vector3(z=-0.5 * sz + dpml), 1e-9)) empty_data = sim.get_flux_data(refl) sim.reset_meep() geometry = [mp.Block(mp.Vector3(mp.inf, mp.inf, 0.5 * sz), center=mp.Vector3(z=0.25 * sz), material=mp.Medium(index=3.5))] sim = mp.Simulation(cell_size=cell_size, geometry=geometry, boundary_layers=pml_layers, sources=sources, k_point=k, dimensions=dimensions, resolution=resolution) refl = sim.add_flux(fcen, df, nfreq, refl_fr) sim.load_minus_flux_data(refl, empty_data) sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ex, mp.Vector3(z=-0.5 * sz + dpml), 1e-9)) refl_flux = mp.get_fluxes(refl) freqs = mp.get_flux_freqs(refl) expected = [ (1.25, -1.123696883299492e-6), (1.2755102040816326, -2.5749667658387866e-6), (1.3010204081632653, -5.70480204599006e-6), (1.3265306122448979, -1.2220464827582253e-5), (1.3520408163265305, -2.531247480206961e-5), (1.3775510204081631, -5.069850309492639e-5), (1.4030612244897958, -9.819256552437341e-5), (1.4285714285714284, -1.8390448659017395e-4), (1.454081632653061, -3.330762066794769e-4), (1.4795918367346936, -5.833650417163753e-4), (1.5051020408163263, -9.8807834237052e-4), (1.5306122448979589, -0.001618472171445976), (1.5561224489795915, -0.0025638388059825985), (1.5816326530612241, -0.003927863989816029), (1.6071428571428568, -0.005819831283556752), (1.6326530612244894, -0.008339881000982728), (1.658163265306122, -0.011558769654206626), (1.6836734693877546, -0.015494308354153143), (1.7091836734693873, -0.02008850084337135), (1.73469387755102, -0.025190871516857616), (1.7602040816326525, -0.030553756123198477), (1.7857142857142851, -0.03584404966066722), (1.8112244897959178, -0.040672967700428275), (1.8367346938775504, -0.04464118393086191), (1.862244897959183, -0.047392712128477496), (1.8877551020408156, -0.048667403362887635), (1.9132653061224483, -0.048341494285878264), (1.938775510204081, -0.04644739000778679), (1.9642857142857135, -0.043168390293742316), (1.9897959183673462, -0.0388094755730579), (2.0153061224489788, -0.03375052221907117), (2.0408163265306114, -0.02839209067703472), (2.066326530612244, -0.023104245646230648), (2.0918367346938767, -0.01818725699718267), (2.1173469387755093, -0.013849270759480073), (2.142857142857142, -0.010201733597436358), (2.1683673469387745, -0.007269616609175294), (2.193877551020407, -0.005011210495189995), (2.21938775510204, -0.0033417192031464896), (2.2448979591836724, -0.0021557351734376256), (2.270408163265305, -0.0013453062176115673), (2.2959183673469377, -8.121742663131631e-4), (2.3214285714285703, -4.7433135191915683e-4), (2.346938775510203, -2.6799188013374266e-4), (2.3724489795918355, -1.464781343401766e-4), (2.397959183673468, -7.745339273024636e-5), (2.423469387755101, -3.9621374769542025e-5), (2.4489795918367334, -1.9608458558430508e-5), (2.474489795918366, -9.38818477949983e-6), (2.4999999999999987, -4.3484671364929225e-6), ] np.testing.assert_allclose(expected, list(zip(freqs, refl_flux)), rtol=1e-6)
refl_fr = mp.FluxRegion(center=mp.Vector3(-0.5*sx+dpml+0.5,wvg_ycen,0),size=mp.Vector3(0,2*w,0)) refl = sim.add_flux(fcen,df,nfreq,refl_fr) # transmitted flux tran_fr = mp.FluxRegion(center=mp.Vector3(0.5*sx-dpml,wvg_ycen,0),size=mp.Vector3(0,2*w,0)) tran = sim.add_flux(fcen,df,nfreq,tran_fr) pt = mp.Vector3(0.5*sx-dpml-0.5,wvg_ycen) sim.run(until_after_sources=mp.stop_when_fields_decayed(50,mp.Ez,pt,1e-3)) # for normalization run, save flux fields data for reflection plane straight_refl_data = sim.get_flux_data(refl) # save incident power for transmission plane straight_tran_flux = mp.get_fluxes(tran) sim.reset_meep() geometry = [mp.Block(mp.Vector3(sx-pad,w,mp.inf),center=mp.Vector3(-0.5*pad,wvg_ycen),material=mp.Medium(epsilon=12)), mp.Block(mp.Vector3(w,sy-pad,mp.inf),center=mp.Vector3(wvg_xcen,0.5*pad),material=mp.Medium(epsilon=12))] sim = mp.Simulation(cell_size=cell, boundary_layers=pml_layers, geometry=geometry, sources=sources, resolution=resolution) # reflected flux refl = sim.add_flux(fcen, df, nfreq, refl_fr)
boundary_layers=pml_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))) if use_cw_solver: sim.init_sim() sim.solve_cw(tol, max_iters, L) else: 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=pml_layers, geometry=geometry, k_point=k, sources=sources, symmetries=symmetries)
nearfield_box = sim.add_near2far(fcen, 0, 1, mp.Near2FarRegion(mp.Vector3(y=0.5*sxy), size=mp.Vector3(sxy)), mp.Near2FarRegion(mp.Vector3(y=-0.5*sxy), size=mp.Vector3(sxy), weight=-1), mp.Near2FarRegion(mp.Vector3(0.5*sxy), size=mp.Vector3(y=sxy)), mp.Near2FarRegion(mp.Vector3(-0.5*sxy), size=mp.Vector3(y=sxy), weight=-1)) flux_box = sim.add_flux(fcen, 0, 1, mp.FluxRegion(mp.Vector3(y=0.5*sxy), size=mp.Vector3(sxy)), mp.FluxRegion(mp.Vector3(y=-0.5*sxy), size=mp.Vector3(sxy), weight=-1), mp.FluxRegion(mp.Vector3(0.5*sxy), size=mp.Vector3(y=sxy)), mp.FluxRegion(mp.Vector3(-0.5*sxy), size=mp.Vector3(y=sxy), weight=-1)) sim.run(until_after_sources=mp.stop_when_fields_decayed(50, src_cmpt, mp.Vector3(), 1e-8)) near_flux = mp.get_fluxes(flux_box)[0] r = 1000/fcen # half side length of far-field square box OR radius of far-field circle res_ff = 1 # resolution of far fields (points/μm) far_flux_box = (nearfield_box.flux(mp.Y, mp.Volume(center=mp.Vector3(y=r), size=mp.Vector3(2*r)), res_ff)[0] - nearfield_box.flux(mp.Y, mp.Volume(center=mp.Vector3(y=-r), size=mp.Vector3(2*r)), res_ff)[0] + nearfield_box.flux(mp.X, mp.Volume(center=mp.Vector3(r), size=mp.Vector3(y=2*r)), res_ff)[0] - nearfield_box.flux(mp.X, mp.Volume(center=mp.Vector3(-r), size=mp.Vector3(y=2*r)), res_ff)[0]) npts = 100 # number of points in [0,2*pi) range of angles angles = 2*math.pi/npts*np.arange(npts) E = np.zeros((npts,3),dtype=np.complex128) H = np.zeros((npts,3),dtype=np.complex128) for n in range(npts): ff = sim.get_farfield(nearfield_box,
def grating(gp,gh,gdc_list): sx = dpml+dsub+gh+dpad+dpml src_pt = mp.Vector3(-0.5*sx+dpml+0.5*dsub) mon_pt = mp.Vector3(0.5*sx-dpml-0.5*dpad) geometry = [mp.Block(material=glass, size=mp.Vector3(dpml+dsub,mp.inf,mp.inf), center=mp.Vector3(-0.5*sx+0.5*(dpml+dsub)))] num_cells = len(gdc_list) if num_cells == 1: sy = gp cell_size = mp.Vector3(sx,sy,0) sources = [mp.Source(mp.GaussianSource(fcen, fwidth=df), component=mp.Ez, center=src_pt, size=mp.Vector3(y=sy))] sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=pml_layers, k_point=k_point, default_material=glass, sources=sources, symmetries=symmetries) flux_obj = sim.add_flux(fcen, 0, 1, mp.FluxRegion(center=mon_pt, size=mp.Vector3(y=sy))) sim.run(until_after_sources=50) input_flux = mp.get_fluxes(flux_obj) sim.reset_meep() geometry.append(mp.Block(material=glass, size=mp.Vector3(gh,gdc_list[0]*gp,mp.inf), center=mp.Vector3(-0.5*sx+dpml+dsub+0.5*gh))) sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=pml_layers, geometry=geometry, k_point=k_point, sources=sources, symmetries=symmetries) flux_obj = sim.add_flux(fcen, 0, 1, mp.FluxRegion(center=mon_pt, size=mp.Vector3(y=sy))) sim.run(until_after_sources=200) freqs = mp.get_eigenmode_freqs(flux_obj) res = sim.get_eigenmode_coefficients(flux_obj, [1], eig_parity=mp.ODD_Z+mp.EVEN_Y) coeffs = res.alpha mode_tran = abs(coeffs[0,0,0])**2/input_flux[0] mode_phase = np.angle(coeffs[0,0,0]) if mode_phase > 0: mode_phase -= 2*np.pi return mode_tran, mode_phase else: sy = num_cells*gp cell_size = mp.Vector3(sx,sy,0) sources = [mp.Source(mp.GaussianSource(fcen, fwidth=df), component=mp.Ez, center=src_pt, size=mp.Vector3(y=sy))] for j in range(num_cells): geometry.append(mp.Block(material=glass, size=mp.Vector3(gh,gdc_list[j]*gp,mp.inf), center=mp.Vector3(-0.5*sx+dpml+dsub+0.5*gh,-0.5*sy+(j+0.5)*gp))) sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=pml_layers, geometry=geometry, k_point=k_point, sources=sources, symmetries=symmetries) n2f_obj = sim.add_near2far(fcen, 0, 1, mp.Near2FarRegion(center=mon_pt, size=mp.Vector3(y=sy))) sim.run(until_after_sources=500) return abs(sim.get_farfields(n2f_obj, ff_res, center=mp.Vector3(focal_length), size=mp.Vector3(spot_length))['Ez'])**2
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 test_mode_decomposition(self): resolution = 10 w1 = 1 w2 = 2 Lw = 2 dair = 3.0 dpml = 5.0 sy = dpml + dair + w2 + dair + dpml half_w1 = 0.5 * w1 half_w2 = 0.5 * w2 Si = mp.Medium(epsilon=12.0) boundary_layers = [mp.PML(dpml)] lcen = 6.67 fcen = 1 / lcen symmetries = [mp.Mirror(mp.Y)] Lt = 2 sx = dpml + Lw + Lt + Lw + dpml cell_size = mp.Vector3(sx, sy, 0) prism_x = sx + 1 half_Lt = 0.5 * Lt src_pt = mp.Vector3(-0.5 * sx + dpml + 0.2 * Lw, 0, 0) sources = [mp.EigenModeSource(src=mp.GaussianSource(fcen, fwidth=0.2 * fcen), component=mp.Ez, center=src_pt, size=mp.Vector3(0, sy - 2 * dpml, 0), eig_match_freq=True, eig_parity=mp.ODD_Z + mp.EVEN_Y)] vertices = [mp.Vector3(-prism_x, half_w1), mp.Vector3(prism_x, half_w1), mp.Vector3(prism_x, -half_w1), mp.Vector3(-prism_x, -half_w1)] sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=boundary_layers, geometry=[mp.Prism(vertices, height=mp.inf, material=Si)], sources=sources, symmetries=symmetries) mon_pt = mp.Vector3(-0.5 * sx + dpml + 0.5 * Lw, 0, 0) flux = sim.add_flux(fcen, 0, 1, mp.FluxRegion(center=mon_pt, size=mp.Vector3(0, sy - 2 * dpml, 0))) sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, src_pt, 1e-9)) res = sim.get_eigenmode_coefficients(flux, [1], eig_parity=mp.ODD_Z + mp.EVEN_Y) incident_coeffs = res.alpha incident_flux = mp.get_fluxes(flux) incident_flux_data = sim.get_flux_data(flux) sim.reset_meep() vertices = [mp.Vector3(-prism_x, half_w1), mp.Vector3(-half_Lt, half_w1), mp.Vector3(half_Lt, half_w2), mp.Vector3(prism_x, half_w2), mp.Vector3(prism_x, -half_w2), mp.Vector3(half_Lt, -half_w2), mp.Vector3(-half_Lt, -half_w1), mp.Vector3(-prism_x, -half_w1)] sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=boundary_layers, geometry=[mp.Prism(vertices, height=mp.inf, material=Si)], sources=sources, symmetries=symmetries) refl_flux = sim.add_flux(fcen, 0, 1, mp.FluxRegion(center=mon_pt, size=mp.Vector3(0, sy - 2 * dpml, 0))) sim.load_minus_flux_data(refl_flux, incident_flux_data) sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, src_pt, 1e-9)) res = sim.get_eigenmode_coefficients(refl_flux, [1], eig_parity=mp.ODD_Z + mp.EVEN_Y) coeffs = res.alpha taper_flux = mp.get_fluxes(refl_flux) self.assertAlmostEqual(abs(coeffs[0, 0, 1])**2 / abs(incident_coeffs[0, 0, 0])**2, -taper_flux[0] / incident_flux[0], places=4)
def run_mode_coeffs(self, mode_num, kpoint_func, nf=1, resolution=15): w = 1 # width of waveguide L = 10 # length of waveguide Si = mp.Medium(epsilon=12.0) dair = 3.0 dpml = 3.0 sx = dpml + L + dpml sy = dpml + dair + w + dair + dpml cell_size = mp.Vector3(sx, sy, 0) prism_x = sx + 1 prism_y = w / 2 vertices = [mp.Vector3(-prism_x, prism_y), mp.Vector3(prism_x, prism_y), mp.Vector3(prism_x, -prism_y), mp.Vector3(-prism_x, -prism_y)] geometry = [mp.Prism(vertices, height=mp.inf, material=Si)] boundary_layers = [mp.PML(dpml)] # mode frequency fcen = 0.20 # > 0.5/sqrt(11) to have at least 2 modes df = 0.5*fcen source=mp.EigenModeSource(src=mp.GaussianSource(fcen, fwidth=df), eig_band=mode_num, size=mp.Vector3(0,sy-2*dpml,0), center=mp.Vector3(-0.5*sx+dpml,0,0), eig_match_freq=True, eig_resolution=2*resolution) sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=boundary_layers, geometry=geometry, sources=[source], symmetries=[mp.Mirror(mp.Y, phase=1 if mode_num % 2 == 1 else -1)]) xm = 0.5*sx - dpml # x-coordinate of monitor mflux = sim.add_mode_monitor(fcen, df, nf, mp.ModeRegion(center=mp.Vector3(xm,0), size=mp.Vector3(0,sy-2*dpml))) mode_flux = sim.add_flux(fcen, df, nf, mp.FluxRegion(center=mp.Vector3(xm,0), size=mp.Vector3(0,sy-2*dpml))) # sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, mp.Vector3(-0.5*sx+dpml,0), 1e-10)) sim.run(until_after_sources=200) ################################################## # If the number of analysis frequencies is >1, we # are testing the unit-power normalization # of the eigenmode source: we observe the total # power flux through the mode_flux monitor (which # equals the total power emitted by the source as # there is no scattering in this ideal waveguide) # and check that it agrees with the prediction # of the eig_power() class method in EigenmodeSource. ################################################## if nf>1: power_observed=mp.get_fluxes(mode_flux) freqs=mp.get_flux_freqs(mode_flux) power_expected=[source.eig_power(f) for f in freqs] return freqs, power_expected, power_observed modes_to_check = [1, 2] # indices of modes for which to compute expansion coefficients res = sim.get_eigenmode_coefficients(mflux, modes_to_check, kpoint_func=kpoint_func) self.assertTrue(res.kpoints[0].close(mp.Vector3(0.604301, 0, 0))) self.assertTrue(res.kpoints[1].close(mp.Vector3(0.494353, 0, 0), tol=1e-2)) self.assertTrue(res.kdom[0].close(mp.Vector3(0.604301, 0, 0))) self.assertTrue(res.kdom[1].close(mp.Vector3(0.494353, 0, 0), tol=1e-2)) mode_power = mp.get_fluxes(mode_flux)[0] TestPassed = True TOLERANCE = 5.0e-3 c0 = res.alpha[mode_num - 1, 0, 0] # coefficient of forward-traveling wave for mode #mode_num for nm in range(1, len(modes_to_check)+1): if nm != mode_num: cfrel = np.abs(res.alpha[nm - 1, 0, 0]) / np.abs(c0) cbrel = np.abs(res.alpha[nm - 1, 0, 1]) / np.abs(c0) if cfrel > TOLERANCE or cbrel > TOLERANCE: TestPassed = False self.sim = sim # test 1: coefficient of excited mode >> coeffs of all other modes self.assertTrue(TestPassed, msg="cfrel: {}, cbrel: {}".format(cfrel, cbrel)) # test 2: |mode coeff|^2 = power self.assertAlmostEqual(mode_power / abs(c0**2), 1.0, places=1) return res
def test_farfield(self): resolution = 50 sxy = 4 dpml = 1 cell = mp.Vector3(sxy+2*dpml,sxy+2*dpml,0) pml_layers = mp.PML(dpml) fcen = 1.0 df = 0.4 sources = mp.Source(src=mp.GaussianSource(fcen,fwidth=df), center=mp.Vector3(), component=mp.Ez) symmetries = [mp.Mirror(mp.X), mp.Mirror(mp.Y)] sim = mp.Simulation(cell_size=cell, resolution=resolution, sources=[sources], symmetries=symmetries, boundary_layers=[pml_layers]) nearfield_box = sim.add_near2far(fcen, 0, 1, mp.Near2FarRegion(mp.Vector3(y=0.5*sxy), size=mp.Vector3(sxy)), mp.Near2FarRegion(mp.Vector3(y=-0.5*sxy), size=mp.Vector3(sxy), weight=-1), mp.Near2FarRegion(mp.Vector3(0.5*sxy), size=mp.Vector3(y=sxy)), mp.Near2FarRegion(mp.Vector3(-0.5*sxy), size=mp.Vector3(y=sxy), weight=-1)) flux_box = sim.add_flux(fcen, 0, 1, mp.FluxRegion(mp.Vector3(y=0.5*sxy), size=mp.Vector3(sxy)), mp.FluxRegion(mp.Vector3(y=-0.5*sxy), size=mp.Vector3(sxy), weight=-1), mp.FluxRegion(mp.Vector3(0.5*sxy), size=mp.Vector3(y=sxy)), mp.FluxRegion(mp.Vector3(-0.5*sxy), size=mp.Vector3(y=sxy), weight=-1)) sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, mp.Vector3(), 1e-8)) near_flux = mp.get_fluxes(flux_box)[0] r = 1000/fcen # radius of far field circle npts = 100 # number of points in [0,2*pi) range of angles E = np.zeros((npts,3),dtype=np.complex128) H = np.zeros((npts,3),dtype=np.complex128) for n in range(npts): ff = sim.get_farfield(nearfield_box, mp.Vector3(r*math.cos(2*math.pi*n/npts), r*math.sin(2*math.pi*n/npts))) E[n,:] = [np.conj(ff[j]) for j in range(3)] H[n,:] = [ff[j+3] for j in range(3)] Px = np.real(np.multiply(E[:,1],H[:,2])-np.multiply(E[:,2],H[:,1])) Py = np.real(np.multiply(E[:,2],H[:,0])-np.multiply(E[:,0],H[:,2])) Pr = np.sqrt(np.square(Px)+np.square(Py)) far_flux_circle = np.sum(Pr)*2*np.pi*r/len(Pr) rr = 20/fcen # length of far field square box far_flux_square = (nearfield_box.flux(mp.Y, mp.Volume(center=mp.Vector3(y=0.5*rr), size=mp.Vector3(rr)), resolution)[0] - nearfield_box.flux(mp.Y, mp.Volume(center=mp.Vector3(y=-0.5*rr), size=mp.Vector3(rr)), resolution)[0] + nearfield_box.flux(mp.X, mp.Volume(center=mp.Vector3(0.5*rr), size=mp.Vector3(y=rr)), resolution)[0] - nearfield_box.flux(mp.X, mp.Volume(center=mp.Vector3(-0.5*rr), size=mp.Vector3(y=rr)), resolution)[0]) print("flux:, {:.6f}, {:.6f}, {:.6f}".format(near_flux,far_flux_circle,far_flux_square)) self.assertAlmostEqual(near_flux, far_flux_circle, places=2) self.assertAlmostEqual(far_flux_circle, far_flux_square, places=2) self.assertAlmostEqual(far_flux_square, near_flux, places=2)
def run_bend_flux(self, from_gdsii_file): # Normalization run self.init(no_bend=True, gdsii=from_gdsii_file) self.sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, self.pt, 1e-3)) # Save flux data for use in real run below fdata = self.sim.get_flux_data(self.refl) expected = [ (0.1, 3.65231563251e-05, 3.68932495077e-05), (0.10101010101, 5.55606718876e-05, 5.6065539588e-05), (0.10202020202, 8.38211697478e-05, 8.44909864736e-05), (0.10303030303, 0.000125411162229, 0.000126268639045), (0.10404040404, 0.000186089117531, 0.000187135303398), (0.105050505051, 0.000273848867869, 0.000275039134667), (0.106060606061, 0.000399674037745, 0.000400880269423), (0.107070707071, 0.00057849953593, 0.000579454087881), (0.108080808081, 0.000830418432986, 0.000830635406881), (0.109090909091, 0.00118217282661, 0.00118084271347), (0.110101010101, 0.00166896468348, 0.00166481944189), (0.111111111111, 0.00233661613864, 0.00232776318321), (0.112121212121, 0.00324409729096, 0.00322782257917), (0.113131313131, 0.00446642217385, 0.00443896468822), (0.114141414141, 0.0060978895019, 0.0060541922825), (0.115151515152, 0.00825561352398, 0.00818906047274), (0.116161616162, 0.0110832518495, 0.010985404883), (0.117171717172, 0.0147547920552, 0.0146151488236), (0.118181818182, 0.0194782085272, 0.0192840042241), (0.119191919192, 0.0254987474079, 0.0252348211592), ] res = list(zip(mp.get_flux_freqs(self.trans), mp.get_fluxes(self.trans), mp.get_fluxes(self.refl))) tolerance = 1e-2 if from_gdsii_file else 1e-3 compare_arrays(self, np.array(expected), np.array(res[:20]), tol=tolerance) # Real run self.sim = None self.init(gdsii=from_gdsii_file) # Load flux data obtained from normalization run self.sim.load_minus_flux_data(self.refl, fdata) self.sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, self.pt, 1e-3)) expected = [ (0.09999999999999999, 1.8392235204829767e-5, -7.259467687598002e-6), (0.10101010101010101, 2.7629932558236724e-5, -1.1107162110079347e-5), (0.10202020202020202, 4.1001228946782745e-5, -1.687561915798036e-5), (0.10303030303030304, 6.018966076122556e-5, -2.5425779493709066e-5), (0.10404040404040406, 8.758554071933231e-5, -3.794958119189475e-5), (0.10505050505050507, 1.2656696778129198e-4, -5.612512808928115e-5), (0.10606060606060609, 1.817948859871414e-4, -8.232188174309142e-5), (0.10707070707070711, 2.594514094902856e-4, -1.1981531280672989e-4), (0.10808080808080812, 3.6736164837695035e-4, -1.7300125173897737e-4), (0.10909090909090914, 5.150131339048232e-4, -2.476730940385436e-4), (0.11010101010101016, 7.136181099374187e-4, -3.5145561406042276e-4), (0.11111111111111117, 9.76491765781944e-4, -4.944142331545938e-4), (0.11212121212121219, 0.001320033637882244, -6.897357105189368e-4), (0.11313131313131321, 0.0017653940714397098, -9.543556354451615e-4), (0.11414141414141422, 0.0023404727796352857, -0.0013095604571818236), (0.11515151515151524, 0.0030813962415392098, -0.00178176942635486), (0.11616161616161626, 0.00403238648982478, -0.0024036650652026112), (0.11717171717171727, 0.005243320443599316, -0.003215529845495731), (0.11818181818181829, 0.0067654019326068, -0.004266367104375331), (0.11919191919191931, 0.008646855439680507, -0.005614491919262783), ] res = list(zip(mp.get_flux_freqs(self.trans), mp.get_fluxes(self.trans), mp.get_fluxes(self.refl))) tolerance = 1e-2 if from_gdsii_file else 1e-3 compare_arrays(self, np.array(expected), np.array(res[:20]), tol=tolerance)