def test_set_materials(self): def change_geom(sim): t = sim.meep_time() fn = t * 0.02 geom = [mp.Cylinder(radius=3, material=mp.Medium(index=3.5), center=mp.Vector3(fn, fn)), mp.Ellipsoid(size=mp.Vector3(1, 2, mp.inf), center=mp.Vector3(fn, fn))] sim.set_materials(geometry=geom) c = mp.Cylinder(radius=3, material=mp.Medium(index=3.5)) e = mp.Ellipsoid(size=mp.Vector3(1, 2, mp.inf)) sources = mp.Source(src=mp.GaussianSource(1, fwidth=0.1), component=mp.Hz, center=mp.Vector3()) symmetries = [mp.Mirror(mp.X, -1), mp.Mirror(mp.Y, -1)] sim = mp.Simulation(cell_size=mp.Vector3(10, 10), geometry=[c, e], boundary_layers=[mp.PML(1.0)], sources=[sources], symmetries=symmetries, resolution=16) eps = {'arr1': None, 'arr2': None} def get_arr1(sim): eps['arr1'] = sim.get_array(mp.Dielectric, mp.Volume(mp.Vector3(), mp.Vector3(10, 10))) def get_arr2(sim): eps['arr2'] = sim.get_array(mp.Dielectric, mp.Volume(mp.Vector3(), mp.Vector3(10, 10))) sim.run(mp.at_time(50, get_arr1), mp.at_time(100, change_geom), mp.at_end(get_arr2), until=200) self.assertFalse(np.array_equal(eps['arr1'], eps['arr2']))
def test_at_time(self): sim = self.init_simple_simulation() sim.use_output_directory(self.temp_dir) sim.run(mp.at_time(100, mp.output_efield_z), until=200) fname = os.path.join(self.temp_dir, 'simulation-ez-000100.00.h5') self.assertTrue(os.path.exists(fname))
def test_at_time(self): sim = self.init_simple_simulation() sim.run(mp.at_time(100, mp.output_efield_z), until=200) fname = 'simulation-ez-000100.00.h5' self.assertTrue(os.path.exists(fname)) mp.all_wait() if mp.am_master(): os.remove(fname)
def main(from_um_factor, resolution_wlen, courant, submerged_index, displacement, surface_index, wlen_center, wlen_width, nfreq, air_wlen_factor, pml_wlen_factor, flux_wlen_factor, time_factor_cell, second_time_factor, series, folder, parallel, n_processes, split_chunks_evenly): #%% CLASSIC INPUT PARAMETERS """ # Simulation size from_um_factor = 100e-3 # Conversion of 1 μm to my length unit (=100nm/1μm) resolution_wlen = 20 # >=8 pixels per smallest wavelength, i.e. np.floor(8/wvl_min) courant = 0.5 # Nanoparticle specifications: Sphere in Vacuum :) paper = "R" reference = "Meep" displacement = 0 # Displacement of the surface from the bottom of the sphere in nm submerged_index = 1.33 # 1.33 for water surface_index = 1.54 # 1.54 for glass # Frequency and wavelength wlen_center = 650 # Main wavelength range in nm wlen_width = 200 # Wavelength band in nm nfreq = 100 # Box dimensions pml_wlen_factor = 0.38 air_wlen_factor = 0.15 flux_wlen_factor = 0.1 # Simulation time time_factor_cell = 1.2 second_time_factor = 10 # Saving directories series = "1stTest" folder = "Test/TestDipole/DipoleGlass" # Configuration parallel = False n_processes = 1 split_chunks_evenly = True """ #%% MORE INPUT PARAMETERS # Simulation size resolution = (from_um_factor * 1e3) * resolution_wlen / (wlen_center + wlen_width / 2) resolution = int(np.ceil(resolution / 2)) * 2 # Frequency and wavelength cutoff = 3.2 # Gaussian planewave source's parameter of shape nazimuthal = 16 npolar = 20 ### TREATED INPUT PARAMETERS # Nanoparticle specifications: Sphere in Vacuum :) displacement = displacement / (from_um_factor * 1e3) # Now in Meep units # Frequency and wavelength wlen_center = wlen_center / (from_um_factor * 1e3) # Now in Meep units wlen_width = wlen_width / (from_um_factor * 1e3) # Now in Meep units freq_center = 1 / wlen_center # Hz center frequency in Meep units freq_width = 1 / wlen_width # Hz range in Meep units from highest to lowest # Space configuration pml_width = pml_wlen_factor * (wlen_center + wlen_width / 2 ) # 0.5 * max(wlen_range) air_width = air_wlen_factor * (wlen_center + wlen_width / 2) flux_box_size = flux_wlen_factor * (wlen_center + wlen_width / 2) # Computation enlapsed = [] if parallel: np_process = mp.count_processors() else: np_process = 1 # Saving directories if series is None: series = "Test" if folder is None: folder = "Test" params_list = [ "from_um_factor", "resolution_wlen", "resolution", "courant", "submerged_index", "displacement", "surface_index", "wlen_center", "wlen_width", "cutoff", "nfreq", "nazimuthal", "npolar", "flux_box_size", "cell_width", "pml_width", "air_width", "until_after_sources", "time_factor_cell", "second_time_factor", "enlapsed", "parallel", "n_processes", "split_chunks_evenly", "script", "sysname", "path" ] #%% GENERAL GEOMETRY SETUP air_width = air_width - air_width % (1 / resolution) pml_width = pml_width - pml_width % (1 / resolution) pml_layers = [mp.PML(thickness=pml_width)] # symmetries = [mp.Mirror(mp.Y), # mp.Mirror(mp.Z, phase=-1)] # Two mirror planes reduce cell size to 1/4 # Issue related that lead me to comment this lines: # https://github.com/NanoComp/meep/issues/1484 cell_width = 2 * (pml_width + air_width) cell_width = cell_width - cell_width % (1 / resolution) cell_size = mp.Vector3(cell_width, cell_width, cell_width) # surface_center = r/4 - displacement/2 + cell_width/4 # surface_center = surface_center - surface_center%(1/resolution) # displacement = r/2 + cell_width/2 - 2*surface_center displacement = displacement - displacement % (1 / resolution) flux_box_size = flux_box_size - flux_box_size % (1 / resolution) sources = [ mp.Source(mp.GaussianSource(freq_center, fwidth=freq_width, is_integrated=True, cutoff=cutoff), center=mp.Vector3(), component=mp.Ez) ] # Ez-polarized point pulse # (its size parameter is null and it is centered at zero) # >> The planewave source extends into the PML # ==> is_integrated=True must be specified until_after_sources = time_factor_cell * cell_width * submerged_index # Enough time for the pulse to pass through all the cell # Originally: Aprox 3 periods of lowest frequency, using T=λ/c=λ in Meep units # Now: Aprox 3 periods of highest frequency, using T=λ/c=λ in Meep units # if surface_index != 1: # geometry = [mp.Block(material=mp.Medium(index=surface_index), # center=mp.Vector3( # - displacement/2 + cell_width/4, # 0, 0), # size=mp.Vector3( # cell_width/2 + displacement, # cell_width, cell_width))] # else: # geometry = [] # A certain material surface underneath it home = vs.get_home() sysname = vs.get_sys_name() path = os.path.join(home, folder, series) if not os.path.isdir(path) and vm.parallel_assign(0, n_processes, parallel): os.makedirs(path) file = lambda f: os.path.join(path, f) #%% BASE SIMULATION: SETUP measure_ram() params = {} for p in params_list: params[p] = eval(p) sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=pml_layers, sources=sources, k_point=mp.Vector3(), Courant=courant, default_material=mp.Medium(index=submerged_index), output_single_precision=True, split_chunks_evenly=split_chunks_evenly) measure_ram() near2far_box = sim.add_near2far( freq_center, freq_width, nfreq, mp.Near2FarRegion(center=mp.Vector3(x=-flux_box_size / 2), size=mp.Vector3(0, flux_box_size, flux_box_size), weight=-1), mp.Near2FarRegion(center=mp.Vector3(x=+flux_box_size / 2), size=mp.Vector3(0, flux_box_size, flux_box_size), weight=+1), mp.Near2FarRegion(center=mp.Vector3(y=-flux_box_size / 2), size=mp.Vector3(flux_box_size, 0, flux_box_size), weight=-1), mp.Near2FarRegion(center=mp.Vector3(y=+flux_box_size / 2), size=mp.Vector3(flux_box_size, 0, flux_box_size), weight=+1), mp.Near2FarRegion(center=mp.Vector3(z=-flux_box_size / 2), size=mp.Vector3(flux_box_size, flux_box_size, 0), weight=-1), mp.Near2FarRegion(center=mp.Vector3(z=+flux_box_size / 2), size=mp.Vector3(flux_box_size, flux_box_size, 0), weight=+1)) measure_ram() # used_ram.append(used_ram[-1]) #%% BASE SIMULATION: INITIALIZE temp = time() sim.init_sim() enlapsed.append(time() - temp) measure_ram() #%% BASE SIMULATION: SIMULATION :D step_ram_function = lambda sim: measure_ram() temp = time() sim.run(mp.at_beginning(step_ram_function), mp.at_time(int(second_time_factor * until_after_sources / 2), step_ram_function), mp.at_end(step_ram_function), until_after_sources=second_time_factor * until_after_sources) # mp.stop_when_fields_decayed( # np.mean(wlen_range), # dT = mean period of source # mp.Ez, # Component of field to check # mp.Vector3(0.5*cell_width - pml_width, 0, 0), # Where to check # 1e-3)) # Factor to decay enlapsed.append(time() - temp) del temp # Aprox 30 periods of lowest frequency, using T=λ/c=λ in Meep units #%% BASE SIMULATION: ANGULAR PATTERN ANALYSIS freqs = np.linspace(freq_center - freq_center / 2, freq_center + freq_width / 2, nfreq) wlens = 1 / freqs # fraunhofer_distance = 8 * (r**2) / min(wlen_range) # radial_distance = max( 10 * fraunhofer_distance , 1.5 * cell_width/2 ) # radius of far-field circle must be at least Fraunhofer distance radial_distance = cell_width azimuthal_angle = np.arange(0, 2 + 2 / nazimuthal, 2 / nazimuthal) # in multiples of pi polar_angle = np.arange(0, 1 + 1 / npolar, 1 / npolar) poynting_x = [] poynting_y = [] poynting_z = [] poynting_r = [] for phi in azimuthal_angle: poynting_x.append([]) poynting_y.append([]) poynting_z.append([]) poynting_r.append([]) for theta in polar_angle: farfield_dict = sim.get_farfields( near2far_box, 1, where=mp.Volume(center=mp.Vector3( radial_distance * np.cos(np.pi * phi) * np.sin(np.pi * theta), radial_distance * np.sin(np.pi * phi) * np.sin(np.pi * theta), radial_distance * np.cos(np.pi * theta)))) Px = farfield_dict["Ey"] * np.conjugate(farfield_dict["Hz"]) Px -= farfield_dict["Ez"] * np.conjugate(farfield_dict["Hy"]) Py = farfield_dict["Ez"] * np.conjugate(farfield_dict["Hx"]) Py -= farfield_dict["Ex"] * np.conjugate(farfield_dict["Hz"]) Pz = farfield_dict["Ex"] * np.conjugate(farfield_dict["Hy"]) Pz -= farfield_dict["Ey"] * np.conjugate(farfield_dict["Hx"]) Px = np.real(Px) Py = np.real(Py) Pz = np.real(Pz) poynting_x[-1].append(Px) poynting_y[-1].append(Py) poynting_z[-1].append(Pz) poynting_r[-1].append( np.sqrt(np.square(Px) + np.square(Py) + np.square(Pz))) del phi, theta, farfield_dict, Px, Py, Pz poynting_x = np.array(poynting_x) poynting_y = np.array(poynting_y) poynting_z = np.array(poynting_z) poynting_r = np.array(poynting_r) #%% BASE SIMULATION: SAVE DATA for p in params_list: params[p] = eval(p) os.chdir(path) sim.save_near2far("BaseNear2Far", near2far_box) if vm.parallel_assign(0, np_process, parallel): f = h5.File("BaseNear2Far.h5", "r+") for key, par in params.items(): f[list(f.keys())[0]].attrs[key] = par f.close() del f os.chdir(syshome) if vm.parallel_assign(1, np_process, parallel): f = h5.File(file("BaseResults.h5"), "w") f["Px"] = poynting_x f["Py"] = poynting_y f["Pz"] = poynting_z f["Pr"] = poynting_r for dset in f.values(): for key, par in params.items(): dset.attrs[key] = par f.close() del f # if not split_chunks_evenly: # vm.save_chunks(sim, params, path) if parallel: f = h5.File(file("BaseRAM.h5"), "w", driver='mpio', comm=MPI.COMM_WORLD) current_process = mp.my_rank() f.create_dataset("RAM", (len(used_ram), np_process), dtype="float") f["RAM"][:, current_process] = used_ram for a in params: f["RAM"].attrs[a] = params[a] f.create_dataset("SWAP", (len(used_ram), np_process), dtype="int") f["SWAP"][:, current_process] = swapped_ram for a in params: f["SWAP"].attrs[a] = params[a] else: f = h5.File(file("BaseRAM.h5"), "w") f.create_dataset("RAM", data=used_ram) for a in params: f["RAM"].attrs[a] = params[a] f.create_dataset("SWAP", data=swapped_ram) for a in params: f["SWAP"].attrs[a] = params[a] f.close() del f sim.reset_meep() #%% FURTHER SIMULATION if surface_index != 1: #% FURTHER SIMULATION: SETUP measure_ram() params = {} for p in params_list: params[p] = eval(p) sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=pml_layers, sources=sources, k_point=mp.Vector3(), Courant=courant, default_material=mp.Medium(index=surface_index), output_single_precision=True, split_chunks_evenly=split_chunks_evenly) measure_ram() near2far_box = sim.add_near2far( freq_center, freq_width, nfreq, mp.Near2FarRegion(center=mp.Vector3(x=-flux_box_size / 2), size=mp.Vector3(0, flux_box_size, flux_box_size), weight=-1), mp.Near2FarRegion(center=mp.Vector3(x=+flux_box_size / 2), size=mp.Vector3(0, flux_box_size, flux_box_size), weight=+1), mp.Near2FarRegion(center=mp.Vector3(y=-flux_box_size / 2), size=mp.Vector3(flux_box_size, 0, flux_box_size), weight=-1), mp.Near2FarRegion(center=mp.Vector3(y=+flux_box_size / 2), size=mp.Vector3(flux_box_size, 0, flux_box_size), weight=+1), mp.Near2FarRegion(center=mp.Vector3(z=-flux_box_size / 2), size=mp.Vector3(flux_box_size, flux_box_size, 0), weight=-1), mp.Near2FarRegion(center=mp.Vector3(z=+flux_box_size / 2), size=mp.Vector3(flux_box_size, flux_box_size, 0), weight=+1)) measure_ram() # used_ram.append(used_ram[-1]) #% FURTHER SIMULATION: INITIALIZE temp = time() sim.init_sim() enlapsed.append(time() - temp) measure_ram() #% FURTHER SIMULATION: SIMULATION :D step_ram_function = lambda sim: measure_ram() temp = time() sim.run(mp.at_beginning(step_ram_function), mp.at_time(int(second_time_factor * until_after_sources / 2), step_ram_function), mp.at_end(step_ram_function), until_after_sources=second_time_factor * until_after_sources) # mp.stop_when_fields_decayed( # np.mean(wlen_range), # dT = mean period of source # mp.Ez, # Component of field to check # mp.Vector3(0.5*cell_width - pml_width, 0, 0), # Where to check # 1e-3)) # Factor to decay enlapsed.append(time() - temp) del temp # Aprox 30 periods of lowest frequency, using T=λ/c=λ in Meep units #% FURTHER SIMULATION: ANGULAR PATTERN ANALYSIS poynting_x2 = [] poynting_y2 = [] poynting_z2 = [] poynting_r2 = [] for phi in azimuthal_angle: poynting_x2.append([]) poynting_y2.append([]) poynting_z2.append([]) poynting_r2.append([]) for theta in polar_angle: farfield_dict = sim.get_farfields( near2far_box, 1, where=mp.Volume(center=mp.Vector3( radial_distance * np.cos(np.pi * phi) * np.sin(np.pi * theta), radial_distance * np.sin(np.pi * phi) * np.sin(np.pi * theta), radial_distance * np.cos(np.pi * theta)))) Px = farfield_dict["Ey"] * np.conjugate(farfield_dict["Hz"]) Px -= farfield_dict["Ez"] * np.conjugate(farfield_dict["Hy"]) Py = farfield_dict["Ez"] * np.conjugate(farfield_dict["Hx"]) Py -= farfield_dict["Ex"] * np.conjugate(farfield_dict["Hz"]) Pz = farfield_dict["Ex"] * np.conjugate(farfield_dict["Hy"]) Pz -= farfield_dict["Ey"] * np.conjugate(farfield_dict["Hx"]) Px = np.real(Px) Py = np.real(Py) Pz = np.real(Pz) poynting_x2[-1].append(Px) poynting_y2[-1].append(Py) poynting_z2[-1].append(Pz) poynting_r2[-1].append( np.sqrt(np.square(Px) + np.square(Py) + np.square(Pz))) del phi, theta, farfield_dict, Px, Py, Pz poynting_x2 = np.array(poynting_x2) poynting_y2 = np.array(poynting_y2) poynting_z2 = np.array(poynting_z2) poynting_r2 = np.array(poynting_r2) #% FURTHER SIMULATION: SAVE DATA for p in params_list: params[p] = eval(p) os.chdir(path) sim.save_near2far("FurtherNear2Far", near2far_box) if vm.parallel_assign(0, np_process, parallel): f = h5.File("FurtherNear2Far.h5", "r+") for key, par in params.items(): f[list(f.keys())[0]].attrs[key] = par f.close() del f os.chdir(syshome) if vm.parallel_assign(1, np_process, parallel): f = h5.File(file("FurtherResults.h5"), "w") f["Px"] = poynting_x2 f["Py"] = poynting_y2 f["Pz"] = poynting_z2 f["Pr"] = poynting_r2 for dset in f.values(): for key, par in params.items(): dset.attrs[key] = par f.close() del f # if not split_chunks_evenly: # vm.save_chunks(sim, params, path) if parallel: f = h5.File(file("FurtherRAM.h5"), "w", driver='mpio', comm=MPI.COMM_WORLD) current_process = mp.my_rank() f.create_dataset("RAM", (len(used_ram), np_process), dtype="float") f["RAM"][:, current_process] = used_ram for a in params: f["RAM"].attrs[a] = params[a] f.create_dataset("SWAP", (len(used_ram), np_process), dtype="int") f["SWAP"][:, current_process] = swapped_ram for a in params: f["SWAP"].attrs[a] = params[a] else: f = h5.File(file("FurtherRAM.h5"), "w") f.create_dataset("RAM", data=used_ram) for a in params: f["RAM"].attrs[a] = params[a] f.create_dataset("SWAP", data=swapped_ram) for a in params: f["SWAP"].attrs[a] = params[a] f.close() del f #%% NORMALIZE AND REARANGE DATA if surface_index != 1: max_poynting_r = np.max( [np.max(np.abs(poynting_r)), np.max(np.abs(poynting_r2))]) else: max_poynting_r = np.max(np.abs(poynting_r)) poynting_x = np.array(poynting_x) / max_poynting_r poynting_y = np.array(poynting_y) / max_poynting_r poynting_z = np.array(poynting_z) / max_poynting_r poynting_r = np.array(poynting_r) / max_poynting_r if surface_index != 1: poynting_x0 = np.array(poynting_x) poynting_y0 = np.array(poynting_y) poynting_z0 = np.array(poynting_z) poynting_r0 = np.array(poynting_r) poynting_x2 = np.array(poynting_x2) / max_poynting_r poynting_y2 = np.array(poynting_y2) / max_poynting_r poynting_z2 = np.array(poynting_z2) / max_poynting_r poynting_r2 = np.array(poynting_r2) / max_poynting_r #%% """ poynting_x = np.array(poynting_x0) poynting_y = np.array(poynting_y0) poynting_z = np.array(poynting_z0) poynting_r = np.array(poynting_r0) """ if surface_index != 1: polar_limit = np.arcsin(displacement / radial_distance) + .5 for i in range(len(polar_angle)): if polar_angle[i] > polar_limit: index_limit = i break poynting_x[:, index_limit:, :] = poynting_x2[:, index_limit:, :] poynting_y[:, index_limit:, :] = poynting_y2[:, index_limit:, :] poynting_z[:, index_limit:, :] = poynting_z2[:, index_limit:, :] poynting_r[:, index_limit:, :] = poynting_r2[:, index_limit:, :] poynting_x[:, index_limit - 1, :] = np.array([[ np.mean([p2, p0]) for p2, p0 in zip(poy2, poy0) ] for poy2, poy0 in zip(poynting_x2[:, index_limit - 1, :], poynting_x0[:, index_limit - 1, :])]) poynting_y[:, index_limit - 1, :] = np.array([[ np.mean([p2, p0]) for p2, p0 in zip(poy2, poy0) ] for poy2, poy0 in zip(poynting_y2[:, index_limit - 1, :], poynting_y0[:, index_limit - 1, :])]) poynting_z[:, index_limit - 1, :] = np.array([[ np.mean([p2, p0]) for p2, p0 in zip(poy2, poy0) ] for poy2, poy0 in zip(poynting_z2[:, index_limit - 1, :], poynting_z0[:, index_limit - 1, :])]) poynting_r[:, index_limit - 1, :] = np.sqrt( np.squared(poynting_x[:, index_limit - 1, :]) + np.squared(poynting_y[:, index_limit - 1, :]) + np.squared(poynting_y[:, index_limit - 1, :])) #%% SAVE FINAL DATA if surface_index != 1 and vm.parallel_assign(0, np_process, parallel): os.remove(file("BaseRAM.h5")) os.rename(file("FurtherRAM.h5"), file("RAM.h5")) elif vm.parallel_assign(0, np_process, parallel): os.rename(file("BaseRAM.h5"), file("RAM.h5")) #%% PLOT ANGULAR PATTERN IN 3D if vm.parallel_assign(1, np_process, parallel): freq_index = np.argmin(np.abs(freqs - freq_center)) fig = plt.figure() plt.suptitle( f'Angular Pattern of point dipole molecule at {from_um_factor * 1e3 * wlen_center:.0f} nm' ) ax = fig.add_subplot(1, 1, 1, projection='3d') ax.plot_surface(poynting_x[:, :, freq_index], poynting_y[:, :, freq_index], poynting_z[:, :, freq_index], cmap=plt.get_cmap('jet'), linewidth=1, antialiased=False, alpha=0.5) ax.set_xlabel(r"$P_x$") ax.set_ylabel(r"$P_y$") ax.set_zlabel(r"$P_z$") plt.savefig(file("AngularPattern.png")) #%% PLOT ANGULAR PATTERN PROFILE FOR DIFFERENT POLAR ANGLES if vm.parallel_assign(0, np_process, parallel): freq_index = np.argmin(np.abs(freqs - freq_center)) index = [ list(polar_angle).index(alpha) for alpha in [0, .25, .5, .75, 1] ] plt.figure() plt.suptitle( f'Angular Pattern of point dipole molecule at {from_um_factor * 1e3 * wlen_center:.0f} nm' ) ax_plain = plt.axes() for i in index: ax_plain.plot(poynting_x[:, i, freq_index], poynting_y[:, i, freq_index], ".-", label=rf"$\theta$ = {polar_angle[i]:.2f} $\pi$") plt.legend() ax_plain.set_xlabel(r"$P_x$") ax_plain.set_ylabel(r"$P_y$") ax_plain.set_aspect("equal") plt.savefig(file("AngularPolar.png")) #%% PLOT ANGULAR PATTERN PROFILE FOR DIFFERENT AZIMUTHAL ANGLES if vm.parallel_assign(1, np_process, parallel): freq_index = np.argmin(np.abs(freqs - freq_center)) index = [ list(azimuthal_angle).index(alpha) for alpha in [0, .25, .5, .75, 1, 1.25, 1.5, 1.75, 2] ] plt.figure() plt.suptitle( f'Angular Pattern of point dipole molecule at {from_um_factor * 1e3 * wlen_center:.0f} nm' ) ax_plain = plt.axes() for i in index: ax_plain.plot(poynting_x[i, :, freq_index], poynting_z[i, :, freq_index], ".-", label=rf"$\phi$ = {azimuthal_angle[i]:.2f} $\pi$") plt.legend() ax_plain.set_xlabel(r"$P_x$") ax_plain.set_ylabel(r"$P_z$") plt.savefig(file("AngularAzimuthal.png")) if vm.parallel_assign(0, np_process, parallel): freq_index = np.argmin(np.abs(freqs - freq_center)) index = [ list(azimuthal_angle).index(alpha) for alpha in [0, .25, .5, .75, 1, 1.25, 1.5, 1.75, 2] ] plt.figure() plt.suptitle( f'Angular Pattern of point dipole molecule at {from_um_factor * 1e3 * wlen_center:.0f} nm' ) ax_plain = plt.axes() for i in index: ax_plain.plot(np.sqrt( np.square(poynting_x[i, :, freq_index]) + np.square(poynting_y[i, :, freq_index])), poynting_z[i, :, freq_index], ".-", label=rf"$\phi$ = {azimuthal_angle[i]:.2f} $\pi$") plt.legend() ax_plain.set_xlabel(r"$P_\rho$") ax_plain.set_ylabel(r"$P_z$") plt.savefig(file("AngularAzimuthalAbs.png"))
def main(from_um_factor, resolution, courant, r, material, paper, reference, submerged_index, displacement, surface_index, wlen_range, nfreq, air_r_factor, pml_wlen_factor, flux_r_factor, time_factor_cell, second_time_factor, series, folder, parallel, n_processes, n_cores, n_nodes, split_chunks_evenly, load_flux, load_chunks, near2far): #%% CLASSIC INPUT PARAMETERS """ # Simulation size from_um_factor = 10e-3 # Conversion of 1 μm to my length unit (=10nm/1μm) resolution = 2 # >=8 pixels per smallest wavelength, i.e. np.floor(8/wvl_min) courant = 0.5 # Nanoparticle specifications: Sphere in Vacuum :) r = 51.5 # Radius of sphere in nm paper = "R" reference = "Meep" displacement = 0 # Displacement of the surface from the bottom of the sphere in nm submerged_index = 1 # 1.33 for water surface_index = 1 # 1.54 for glass # Frequency and wavelength wlen_range = np.array([350,500]) # Wavelength range in nm nfreq = 100 # Box dimensions pml_wlen_factor = 0.38 air_r_factor = 0.5 flux_r_factor = 0 #0.1 # Simulation time time_factor_cell = 1.2 second_time_factor = 10 # Saving directories series = "SilverRes4" folder = "Test/TestSilver" # Configuration parallel = False n_processes = 1 n_cores = 1 n_nodes = 1 split_chunks_evenly = True load_flux = False load_chunks = True near2far = False """ #%% MORE INPUT PARAMETERS # Frequency and wavelength cutoff = 3.2 # Gaussian planewave source's parameter of shape nazimuthal = 16 npolar = 20 ### TREATED INPUT PARAMETERS # Nanoparticle specifications: Sphere in Vacuum :) r = r / (from_um_factor * 1e3) # Now in Meep units if reference == "Meep": medium = vmt.import_medium(material, from_um_factor=from_um_factor, paper=paper) # Importing material constants dependant on frequency from Meep Library elif reference == "RIinfo": medium = vmt.MediumFromFile(material, paper=paper, reference=reference, from_um_factor=from_um_factor) # Importing material constants dependant on frequency from external file else: raise ValueError("Reference for medium not recognized. Sorry :/") displacement = displacement / (from_um_factor * 1e3) # Now in Meep units # Frequency and wavelength wlen_range = np.array(wlen_range) wlen_range = wlen_range / (from_um_factor * 1e3) # Now in Meep units freq_range = 1 / wlen_range # Hz range in Meep units from highest to lowest freq_center = np.mean(freq_range) freq_width = max(freq_range) - min(freq_range) # Space configuration pml_width = pml_wlen_factor * max(wlen_range) # 0.5 * max(wlen_range) air_width = air_r_factor * r # 0.5 * max(wlen_range) flux_box_size = 2 * (1 + flux_r_factor) * r # Saving directories if series is None: series = "Test" if folder is None: folder = "Test" params_list = [ "from_um_factor", "resolution", "courant", "material", "r", "paper", "reference", "submerged_index", "displacement", "surface_index", "wlen_range", "nfreq", "nazimuthal", "npolar", "cutoff", "flux_box_size", "cell_width", "pml_width", "air_width", "source_center", "until_after_sources", "time_factor_cell", "second_time_factor", "enlapsed", "parallel", "n_processes", "n_cores", "n_nodes", "split_chunks_evenly", "near2far", "script", "sysname", "path" ] #%% GENERAL GEOMETRY SETUP air_width = air_width - air_width % (1 / resolution) pml_width = pml_width - pml_width % (1 / resolution) pml_layers = [mp.PML(thickness=pml_width)] # symmetries = [mp.Mirror(mp.Y), # mp.Mirror(mp.Z, phase=-1)] # Two mirror planes reduce cell size to 1/4 # Issue related that lead me to comment this lines: # https://github.com/NanoComp/meep/issues/1484 cell_width = 2 * (pml_width + air_width + r) cell_width = cell_width - cell_width % (1 / resolution) cell_size = mp.Vector3(cell_width, cell_width, cell_width) # surface_center = r/4 - displacement/2 + cell_width/4 # surface_center = surface_center - surface_center%(1/resolution) # displacement = r/2 + cell_width/2 - 2*surface_center displacement = displacement - displacement % (1 / resolution) flux_box_size = flux_box_size - flux_box_size % (1 / resolution) source_center = -0.5 * cell_width + pml_width sources = [ mp.Source(mp.GaussianSource(freq_center, fwidth=freq_width, is_integrated=True, cutoff=cutoff), center=mp.Vector3(source_center), size=mp.Vector3(0, cell_width, cell_width), component=mp.Ez) ] # Ez-polarized planewave pulse # (its size parameter fills the entire cell in 2d) # >> The planewave source extends into the PML # ==> is_integrated=True must be specified until_after_sources = time_factor_cell * cell_width * submerged_index # Enough time for the pulse to pass through all the cell # Originally: Aprox 3 periods of lowest frequency, using T=λ/c=λ in Meep units # Now: Aprox 3 periods of highest frequency, using T=λ/c=λ in Meep units geometry = [mp.Sphere(material=medium, center=mp.Vector3(), radius=r)] # Au sphere with frequency-dependant characteristics imported from Meep. if surface_index != 1: geometry = [ mp.Block(material=mp.Medium(index=surface_index), center=mp.Vector3( r / 2 - displacement / 2 + cell_width / 4, 0, 0), size=mp.Vector3(cell_width / 2 - r + displacement, cell_width, cell_width)), *geometry ] # A certain material surface underneath it home = vs.get_home() sysname = vs.get_sys_name() path = os.path.join(home, folder, series) if not os.path.isdir(path) and vm.parallel_assign(0, n_processes, parallel): os.makedirs(path) file = lambda f: os.path.join(path, f) # Computation enlapsed = [] parallel_specs = np.array([n_processes, n_cores, n_nodes], dtype=int) max_index = np.argmax(parallel_specs) for index, item in enumerate(parallel_specs): if item == 0: parallel_specs[index] = 1 parallel_specs[0:max_index] = np.full(parallel_specs[0:max_index].shape, max(parallel_specs)) n_processes, n_cores, n_nodes = parallel_specs parallel = max(parallel_specs) > 1 del parallel_specs, max_index, index, item if parallel: np_process = mp.count_processors() else: np_process = 1 #%% FIRST RUN measure_ram() params = {} for p in params_list: params[p] = eval(p) stable, max_courant = vm.check_stability(params) if stable: print("As a whole, the simulation should be stable") else: print("As a whole, the simulation could not be stable") print(f"Recommended maximum courant factor is {max_courant}") if load_flux: try: flux_path = vm.check_midflux(params)[0] flux_needed = False except: flux_needed = True else: flux_needed = True if load_chunks and not split_chunks_evenly: try: chunks_path = vm.check_chunks(params)[0] chunk_layout = os.path.join(chunks_path, "Layout.h5") chunks_needed = False except: chunks_needed = True flux_needed = True else: if not split_chunks_evenly: chunks_needed = True flux_needed = True else: chunk_layout = None chunks_needed = False if chunks_needed: sim = mp.Simulation( resolution=resolution, cell_size=cell_size, boundary_layers=pml_layers, sources=sources, k_point=mp.Vector3(), Courant=courant, default_material=mp.Medium(index=submerged_index), output_single_precision=True, split_chunks_evenly=split_chunks_evenly, # symmetries=symmetries, geometry=geometry) sim.init_sim() chunks_path = vm.save_chunks(sim, params, path) chunk_layout = os.path.join(chunks_path, "Layout.h5") del sim if flux_needed: #% FIRST RUN: SET UP measure_ram() sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=pml_layers, sources=sources, k_point=mp.Vector3(), Courant=courant, default_material=mp.Medium(index=submerged_index), split_chunks_evenly=split_chunks_evenly, chunk_layout=chunk_layout, output_single_precision=True) #, # symmetries=symmetries) # >> k_point zero specifies boundary conditions needed # for the source to be infinitely extended measure_ram() # Scattered power --> Computed by surrounding it with closed DFT flux box # (its size and orientation are irrelevant because of Poynting's theorem) box_x1 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(x=-flux_box_size / 2), size=mp.Vector3(0, flux_box_size, flux_box_size))) box_x2 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(x=+flux_box_size / 2), size=mp.Vector3(0, flux_box_size, flux_box_size))) box_y1 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(y=-flux_box_size / 2), size=mp.Vector3(flux_box_size, 0, flux_box_size))) box_y2 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(y=+flux_box_size / 2), size=mp.Vector3(flux_box_size, 0, flux_box_size))) box_z1 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(z=-flux_box_size / 2), size=mp.Vector3(flux_box_size, flux_box_size, 0))) box_z2 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(z=+flux_box_size / 2), size=mp.Vector3(flux_box_size, flux_box_size, 0))) # Funny you can encase the sphere (r radius) so closely (2r-sided box) measure_ram() if near2far: near2far_box = sim.add_near2far( freq_center, freq_width, nfreq, mp.Near2FarRegion(center=mp.Vector3(x=-flux_box_size / 2), size=mp.Vector3(0, flux_box_size, flux_box_size), weight=-1), mp.Near2FarRegion(center=mp.Vector3(x=+flux_box_size / 2), size=mp.Vector3(0, flux_box_size, flux_box_size), weight=+1), mp.Near2FarRegion(center=mp.Vector3(y=-flux_box_size / 2), size=mp.Vector3(flux_box_size, 0, flux_box_size), weight=-1), mp.Near2FarRegion(center=mp.Vector3(y=+flux_box_size / 2), size=mp.Vector3(flux_box_size, 0, flux_box_size), weight=+1), mp.Near2FarRegion(center=mp.Vector3(z=-flux_box_size / 2), size=mp.Vector3(flux_box_size, flux_box_size, 0), weight=-1), mp.Near2FarRegion(center=mp.Vector3(z=+flux_box_size / 2), size=mp.Vector3(flux_box_size, flux_box_size, 0), weight=+1)) measure_ram() else: near2far_box = None # used_ram.append(used_ram[-1]) #% FIRST RUN: INITIALIZE temp = time() sim.init_sim() enlapsed.append(time() - temp) measure_ram() step_ram_function = lambda sim: measure_ram() #% FIRST RUN: SIMULATION NEEDED TO NORMALIZE temp = time() sim.run(mp.at_beginning(step_ram_function), mp.at_time(int(until_after_sources / 2), step_ram_function), mp.at_end(step_ram_function), until_after_sources=until_after_sources) # mp.stop_when_fields_decayed( # np.mean(wlen_range), # dT = mean period of source # mp.Ez, # Component of field to check # mp.Vector3(0.5*cell_width - pml_width, 0, 0), # Where to check # 1e-3)) # Factor to decay enlapsed.append(time() - temp) #% SAVE MID DATA for p in params_list: params[p] = eval(p) flux_path = vm.save_midflux(sim, box_x1, box_x2, box_y1, box_y2, box_z1, box_z2, near2far_box, params, path) freqs = np.asarray(mp.get_flux_freqs(box_x1)) box_x1_flux0 = np.asarray(mp.get_fluxes(box_x1)) box_x2_flux0 = np.asarray(mp.get_fluxes(box_x2)) box_y1_flux0 = np.asarray(mp.get_fluxes(box_y1)) box_y2_flux0 = np.asarray(mp.get_fluxes(box_y2)) box_z1_flux0 = np.asarray(mp.get_fluxes(box_z1)) box_z2_flux0 = np.asarray(mp.get_fluxes(box_z2)) data_mid = np.array([ 1e3 * from_um_factor / freqs, box_x1_flux0, box_x2_flux0, box_y1_flux0, box_y2_flux0, box_z1_flux0, box_z2_flux0 ]).T header_mid = [ "Longitud de onda [nm]", "Flujo X10 [u.a.]", "Flujo X20 [u.a]", "Flujo Y10 [u.a]", "Flujo Y20 [u.a]", "Flujo Z10 [u.a]", "Flujo Z20 [u.a]" ] if vm.parallel_assign(0, n_processes, parallel): vs.savetxt(file("MidFlux.txt"), data_mid, header=header_mid, footer=params) if not split_chunks_evenly: vm.save_chunks(sim, params, path) if parallel: f = h5.File(file("MidRAM.h5"), "w", driver='mpio', comm=MPI.COMM_WORLD) current_process = mp.my_rank() f.create_dataset("RAM", (len(used_ram), np_process), dtype="float") f["RAM"][:, current_process] = used_ram for a in params: f["RAM"].attrs[a] = params[a] f.create_dataset("SWAP", (len(used_ram), np_process), dtype="int") f["SWAP"][:, current_process] = swapped_ram for a in params: f["SWAP"].attrs[a] = params[a] else: f = h5.File(file("MidRAM.h5"), "w") f.create_dataset("RAM", data=used_ram) for a in params: f["RAM"].attrs[a] = params[a] f.create_dataset("SWAP", data=swapped_ram) for a in params: f["SWAP"].attrs[a] = params[a] f.close() del f #% PLOT FLUX FOURIER MID DATA if vm.parallel_assign(1, np_process, parallel): ylims = (np.min(data_mid[:, 1:]), np.max(data_mid[:, 1:])) ylims = (ylims[0] - .1 * (ylims[1] - ylims[0]), ylims[1] + .1 * (ylims[1] - ylims[0])) fig, ax = plt.subplots(3, 2, sharex=True) fig.subplots_adjust(hspace=0, wspace=.05) for a in ax[:, 1]: a.yaxis.tick_right() a.yaxis.set_label_position("right") for a, h in zip(np.reshape(ax, 6), header_mid[1:]): a.set_ylabel(h) for d, a in zip(data_mid[:, 1:].T, np.reshape(ax, 6)): a.plot(1e3 * from_um_factor / freqs, d) a.set_ylim(*ylims) ax[-1, 0].set_xlabel("Wavelength [nm]") ax[-1, 1].set_xlabel("Wavelength [nm]") plt.savefig(file("MidFlux.png")) del fig, ax, ylims, a, h sim.reset_meep() #%% SECOND RUN: SETUP measure_ram() sim = mp.Simulation( resolution=resolution, cell_size=cell_size, boundary_layers=pml_layers, sources=sources, k_point=mp.Vector3(), Courant=courant, default_material=mp.Medium(index=submerged_index), output_single_precision=True, split_chunks_evenly=split_chunks_evenly, chunk_layout=chunk_layout, # symmetries=symmetries, geometry=geometry) measure_ram() box_x1 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(x=-flux_box_size / 2), size=mp.Vector3(0, flux_box_size, flux_box_size))) box_x2 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(x=+flux_box_size / 2), size=mp.Vector3(0, flux_box_size, flux_box_size))) box_y1 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(y=-flux_box_size / 2), size=mp.Vector3(flux_box_size, 0, flux_box_size))) box_y2 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(y=+flux_box_size / 2), size=mp.Vector3(flux_box_size, 0, flux_box_size))) box_z1 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(z=-flux_box_size / 2), size=mp.Vector3(flux_box_size, flux_box_size, 0))) box_z2 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(z=+flux_box_size / 2), size=mp.Vector3(flux_box_size, flux_box_size, 0))) measure_ram() if near2far: near2far_box = sim.add_near2far( freq_center, freq_width, nfreq, mp.Near2FarRegion(center=mp.Vector3(x=-flux_box_size / 2), size=mp.Vector3(0, flux_box_size, flux_box_size), weight=-1), mp.Near2FarRegion(center=mp.Vector3(x=+flux_box_size / 2), size=mp.Vector3(0, flux_box_size, flux_box_size), weight=+1), mp.Near2FarRegion(center=mp.Vector3(y=-flux_box_size / 2), size=mp.Vector3(flux_box_size, 0, flux_box_size), weight=-1), mp.Near2FarRegion(center=mp.Vector3(y=+flux_box_size / 2), size=mp.Vector3(flux_box_size, 0, flux_box_size), weight=+1), mp.Near2FarRegion(center=mp.Vector3(z=-flux_box_size / 2), size=mp.Vector3(flux_box_size, flux_box_size, 0), weight=-1), mp.Near2FarRegion(center=mp.Vector3(z=+flux_box_size / 2), size=mp.Vector3(flux_box_size, flux_box_size, 0), weight=+1)) measure_ram() else: near2far_box = None # used_ram.append(used_ram[-1]) #%% SECOND RUN: INITIALIZE temp = time() sim.init_sim() enlapsed.append(time() - temp) measure_ram() #%% LOAD FLUX FROM FILE vm.load_midflux(sim, box_x1, box_x2, box_y1, box_y2, box_z1, box_z2, near2far_box, flux_path) measure_ram() freqs = np.asarray(mp.get_flux_freqs(box_x1)) box_x1_flux0 = np.asarray(mp.get_fluxes(box_x1)) box_x1_data = sim.get_flux_data(box_x1) box_x2_data = sim.get_flux_data(box_x2) box_y1_data = sim.get_flux_data(box_y1) box_y2_data = sim.get_flux_data(box_y2) box_z1_data = sim.get_flux_data(box_z1) box_z2_data = sim.get_flux_data(box_z2) if near2far: near2far_data = sim.get_near2far_data(near2far_box) temp = time() sim.load_minus_flux_data(box_x1, box_x1_data) sim.load_minus_flux_data(box_x2, box_x2_data) sim.load_minus_flux_data(box_y1, box_y1_data) sim.load_minus_flux_data(box_y2, box_y2_data) sim.load_minus_flux_data(box_z1, box_z1_data) sim.load_minus_flux_data(box_z2, box_z2_data) if near2far: sim.load_minus_near2far_data(near2far_box, near2far_data) enlapsed.append(time() - temp) del box_x1_data, box_x2_data, box_y1_data, box_y2_data del box_z1_data, box_z2_data if near2far: del near2far_data measure_ram() #%% SECOND RUN: SIMULATION :D step_ram_function = lambda sim: measure_ram() temp = time() sim.run(mp.at_beginning(step_ram_function), mp.at_time(int(second_time_factor * until_after_sources / 2), step_ram_function), mp.at_end(step_ram_function), until_after_sources=second_time_factor * until_after_sources) # mp.stop_when_fields_decayed( # np.mean(wlen_range), # dT = mean period of source # mp.Ez, # Component of field to check # mp.Vector3(0.5*cell_width - pml_width, 0, 0), # Where to check # 1e-3)) # Factor to decay enlapsed.append(time() - temp) del temp # Aprox 30 periods of lowest frequency, using T=λ/c=λ in Meep units box_x1_flux = np.asarray(mp.get_fluxes(box_x1)) box_x2_flux = np.asarray(mp.get_fluxes(box_x2)) box_y1_flux = np.asarray(mp.get_fluxes(box_y1)) box_y2_flux = np.asarray(mp.get_fluxes(box_y2)) box_z1_flux = np.asarray(mp.get_fluxes(box_z1)) box_z2_flux = np.asarray(mp.get_fluxes(box_z2)) #%% SCATTERING ANALYSIS scatt_flux = box_x1_flux - box_x2_flux scatt_flux = scatt_flux + box_y1_flux - box_y2_flux scatt_flux = scatt_flux + box_z1_flux - box_z2_flux intensity = box_x1_flux0 / (flux_box_size)**2 # Flux of one of the six monitor planes / Área # (the closest one, facing the planewave source) # This is why the six sides of the flux box are separated # (Otherwise, the box could've been one flux object with weights ±1 per side) scatt_cross_section = np.divide(scatt_flux, intensity) # Scattering cross section σ = # = scattered power in all directions / incident intensity. scatt_eff_meep = -1 * scatt_cross_section / (np.pi * r**2) # Scattering efficiency = # = scattering cross section / cross sectional area of the sphere freqs = np.array(freqs) scatt_eff_theory = [ ps.MieQ(np.sqrt(medium.epsilon(f)[0, 0] * medium.mu(f)[0, 0]), 1e3 * from_um_factor / f, 2 * r * 1e3 * from_um_factor, nMedium=submerged_index, asDict=True)['Qsca'] for f in freqs ] # The simulation results are validated by comparing with # analytic theory of PyMieScatt module #%% ANGULAR PATTERN ANALYSIS if near2far: fraunhofer_distance = 8 * (r**2) / min(wlen_range) radial_distance = max(10 * fraunhofer_distance, 1.5 * cell_width / 2) # radius of far-field circle must be at least Fraunhofer distance azimuthal_angle = np.arange(0, 2 + 2 / nazimuthal, 2 / nazimuthal) # in multiples of pi polar_angle = np.arange(0, 1 + 1 / npolar, 1 / npolar) poynting_x = [] poynting_y = [] poynting_z = [] poynting_r = [] for phi in azimuthal_angle: poynting_x.append([]) poynting_y.append([]) poynting_z.append([]) poynting_r.append([]) for theta in polar_angle: farfield_dict = sim.get_farfields( near2far_box, 1, where=mp.Volume(center=mp.Vector3( radial_distance * np.cos(np.pi * phi) * np.sin(np.pi * theta), radial_distance * np.sin(np.pi * phi) * np.sin(np.pi * theta), radial_distance * np.cos(np.pi * theta)))) Px = farfield_dict["Ey"] * np.conjugate(farfield_dict["Hz"]) Px -= farfield_dict["Ez"] * np.conjugate(farfield_dict["Hy"]) Py = farfield_dict["Ez"] * np.conjugate(farfield_dict["Hx"]) Py -= farfield_dict["Ex"] * np.conjugate(farfield_dict["Hz"]) Pz = farfield_dict["Ex"] * np.conjugate(farfield_dict["Hy"]) Pz -= farfield_dict["Ey"] * np.conjugate(farfield_dict["Hx"]) Px = np.real(Px) Py = np.real(Py) Pz = np.real(Pz) poynting_x[-1].append(Px) poynting_y[-1].append(Py) poynting_z[-1].append(Pz) poynting_r[-1].append( np.sqrt(np.square(Px) + np.square(Py) + np.square(Pz))) poynting_x = np.array(poynting_x) poynting_y = np.array(poynting_y) poynting_z = np.array(poynting_z) poynting_r = np.array(poynting_r) #%% SAVE FINAL DATA for p in params_list: params[p] = eval(p) data = np.array( [1e3 * from_um_factor / freqs, scatt_eff_meep, scatt_eff_theory]).T header = [ "Longitud de onda [nm]", "Sección eficaz efectiva (Meep) [u.a.]", "Sección eficaz efectiva (Theory) [u.a.]" ] data_base = np.array([ 1e3 * from_um_factor / freqs, box_x1_flux0, box_x1_flux, box_x2_flux, box_y1_flux, box_y2_flux, box_z1_flux, box_z2_flux, intensity, scatt_flux, scatt_cross_section ]).T header_base = [ "Longitud de onda [nm]", "Flujo X10 [u.a.]", "Flujo X1 [u.a]", "Flujo X2 [u.a]", "Flujo Y1 [u.a]", "Flujo Y2 [u.a]", "Flujo Z1 [u.a]", "Flujo Z2 [u.a]", "Intensidad incidente [u.a.]", "Flujo scattereado [u.a.]", "Sección eficaz de scattering [u.a.]" ] if vm.parallel_assign(0, np_process, parallel): vs.savetxt(file("Results.txt"), data, header=header, footer=params) vs.savetxt(file("BaseResults.txt"), data_base, header=header_base, footer=params) if near2far: header_near2far = [ "Poynting medio Px [u.a.]", "Poynting medio Py [u.a.]", "Poynting medio Pz [u.a.]", "Poynting medio Pr [u.a.]" ] data_near2far = [ poynting_x.reshape(poynting_x.size), poynting_y.reshape(poynting_y.size), poynting_z.reshape(poynting_z.size), poynting_r.reshape(poynting_r.size) ] if vm.parallel_assign(1, np_process, parallel): vs.savetxt(file("Near2FarResults.txt"), data_near2far, header=header_near2far, footer=params) if not split_chunks_evenly: vm.save_chunks(sim, params, path) if parallel: f = h5.File(file("RAM.h5"), "w", driver='mpio', comm=MPI.COMM_WORLD) current_process = mp.my_rank() f.create_dataset("RAM", (len(used_ram), np_process), dtype="float") f["RAM"][:, current_process] = used_ram for a in params: f["RAM"].attrs[a] = params[a] f.create_dataset("SWAP", (len(used_ram), np_process), dtype="int") f["SWAP"][:, current_process] = swapped_ram for a in params: f["SWAP"].attrs[a] = params[a] else: f = h5.File(file("RAM.h5"), "w") f.create_dataset("RAM", data=used_ram) for a in params: f["RAM"].attrs[a] = params[a] f.create_dataset("SWAP", data=swapped_ram) for a in params: f["SWAP"].attrs[a] = params[a] f.close() del f if flux_needed and vm.parallel_assign(0, np_process, parallel): os.remove(file("MidRAM.h5")) #%% PLOT ALL TOGETHER if vm.parallel_assign(0, np_process, parallel) and surface_index == 1: plt.figure() plt.plot(1e3 * from_um_factor / freqs, scatt_eff_meep, 'bo-', label='Meep') plt.plot(1e3 * from_um_factor / freqs, scatt_eff_theory, 'ro-', label='Theory') plt.xlabel('Wavelength [nm]') plt.ylabel('Scattering efficiency [σ/πr$^{2}$]') plt.legend() plt.title('Scattering of Au Sphere With {:.1f} nm Radius'.format( r * from_um_factor * 1e3)) plt.tight_layout() plt.savefig(file("Comparison.png")) #%% PLOT SEPARATE if vm.parallel_assign(1, np_process, parallel): plt.figure() plt.plot(1e3 * from_um_factor / freqs, scatt_eff_meep, 'bo-', label='Meep') plt.xlabel('Wavelength [nm]') plt.ylabel('Scattering efficiency [σ/πr$^{2}$]') plt.legend() plt.title('Scattering of Au Sphere With {:.1f} nm Radius'.format( r * from_um_factor * 1e3)) plt.tight_layout() plt.savefig(file("Meep.png")) if vm.parallel_assign(0, np_process, parallel) and surface_index == 1: plt.figure() plt.plot(1e3 * from_um_factor / freqs, scatt_eff_theory, 'ro-', label='Theory') plt.xlabel('Wavelength [nm]') plt.ylabel('Scattering efficiency [σ/πr$^{2}$]') plt.legend() plt.title('Scattering of Au Sphere With {:.1f} nm Radius'.format(r * 10)) plt.tight_layout() plt.savefig(file("Theory.png")) #%% PLOT ONE ABOVE THE OTHER if vm.parallel_assign(1, np_process, parallel) and surface_index == 1: fig, axes = plt.subplots(nrows=2, sharex=True) fig.subplots_adjust(hspace=0) plt.suptitle('Scattering of Au Sphere With {:.1f} nm Radius'.format( r * from_um_factor * 1e3)) axes[0].plot(1e3 * from_um_factor / freqs, scatt_eff_meep, 'bo-', label='Meep') axes[0].yaxis.tick_right() axes[0].set_ylabel('Scattering efficiency [σ/πr$^{2}$]') axes[0].legend() axes[1].plot(1e3 * from_um_factor / freqs, scatt_eff_theory, 'ro-', label='Theory') axes[1].set_xlabel('Wavelength [nm]') axes[1].set_ylabel('Scattering efficiency [σ/πr$^{2}$]') axes[1].legend() plt.savefig(file("SeparatedComparison.png")) #%% PLOT FLUX FOURIER FINAL DATA if vm.parallel_assign(0, np_process, parallel): ylims = (np.min(data_base[:, 2:8]), np.max(data_base[:, 2:8])) ylims = (ylims[0] - .1 * (ylims[1] - ylims[0]), ylims[1] + .1 * (ylims[1] - ylims[0])) fig, ax = plt.subplots(3, 2, sharex=True) fig.subplots_adjust(hspace=0, wspace=.05) plt.suptitle('Final flux of Au Sphere With {:.1f} nm Radius'.format( r * from_um_factor * 1e3)) for a in ax[:, 1]: a.yaxis.tick_right() a.yaxis.set_label_position("right") for a, h in zip(np.reshape(ax, 6), header_base[1:7]): a.set_ylabel(h) for d, a in zip(data_base[:, 3:9].T, np.reshape(ax, 6)): a.plot(1e3 * from_um_factor / freqs, d) a.set_ylim(*ylims) ax[-1, 0].set_xlabel("Wavelength [nm]") ax[-1, 1].set_xlabel("Wavelength [nm]") plt.savefig(file("FinalFlux.png")) #%% PLOT ANGULAR PATTERN IN 3D if near2far and vm.parallel_assign(1, np_process, parallel): freq_index = np.argmin(np.abs(freqs - freq_center)) fig = plt.figure() plt.suptitle( 'Angular Pattern of Au Sphere With {:.1f} nm Radius at {:.1f} nm'. format(r * from_um_factor * 1e3, from_um_factor * 1e3 / freqs[freq_index])) ax = fig.add_subplot(1, 1, 1, projection='3d') ax.plot_surface(poynting_x[:, :, freq_index], poynting_y[:, :, freq_index], poynting_z[:, :, freq_index], cmap=plt.get_cmap('jet'), linewidth=1, antialiased=False, alpha=0.5) ax.set_xlabel(r"$P_x$") ax.set_ylabel(r"$P_y$") ax.set_zlabel(r"$P_z$") plt.savefig(file("AngularPattern.png")) #%% PLOT ANGULAR PATTERN PROFILE FOR DIFFERENT POLAR ANGLES if near2far and vm.parallel_assign(0, np_process, parallel): freq_index = np.argmin(np.abs(freqs - freq_center)) index = [ list(polar_angle).index(alpha) for alpha in [0, .25, .5, .75, 1] ] plt.figure() plt.suptitle( 'Angular Pattern of Au Sphere With {:.1f} nm Radius at {:.1f} nm'. format(r * from_um_factor * 1e3, from_um_factor * 1e3 / freqs[freq_index])) ax_plain = plt.axes() for i in index: ax_plain.plot(poynting_x[:, i, freq_index], poynting_y[:, i, freq_index], ".-", label=rf"$\theta$ = {polar_angle[i]:.2f} $\pi$") plt.legend() ax_plain.set_xlabel(r"$P_x$") ax_plain.set_ylabel(r"$P_y$") ax_plain.set_aspect("equal") plt.savefig(file("AngularPolar.png")) #%% PLOT ANGULAR PATTERN PROFILE FOR DIFFERENT AZIMUTHAL ANGLES if near2far and vm.parallel_assign(1, np_process, parallel): freq_index = np.argmin(np.abs(freqs - freq_center)) index = [ list(azimuthal_angle).index(alpha) for alpha in [0, .25, .5, .75, 1, 1.25, 1.5, 1.75, 2] ] plt.figure() plt.suptitle( 'Angular Pattern of Au Sphere With {:.1f} nm Radius at {:.1f} nm'. format(r * from_um_factor * 1e3, from_um_factor * 1e3 / freqs[freq_index])) ax_plain = plt.axes() for i in index: ax_plain.plot(poynting_x[i, :, freq_index], poynting_z[i, :, freq_index], ".-", label=rf"$\phi$ = {azimuthal_angle[i]:.2f} $\pi$") plt.legend() ax_plain.set_xlabel(r"$P_x$") ax_plain.set_ylabel(r"$P_z$") plt.savefig(file("AngularAzimuthal.png")) if near2far and vm.parallel_assign(0, np_process, parallel): freq_index = np.argmin(np.abs(freqs - freq_center)) index = [ list(azimuthal_angle).index(alpha) for alpha in [0, .25, .5, .75, 1, 1.25, 1.5, 1.75, 2] ] plt.figure() plt.suptitle( 'Angular Pattern of Au Sphere With {:.1f} nm Radius at {:.1f} nm'. format(r * from_um_factor * 1e3, from_um_factor * 1e3 / freqs[freq_index])) ax_plain = plt.axes() for i in index: ax_plain.plot(np.sqrt( np.square(poynting_x[i, :, freq_index]) + np.square(poynting_y[i, :, freq_index])), poynting_z[i, :, freq_index], ".-", label=rf"$\phi$ = {azimuthal_angle[i]:.2f} $\pi$") plt.legend() ax_plain.set_xlabel(r"$P_\rho$") ax_plain.set_ylabel(r"$P_z$") plt.savefig(file("AngularAzimuthalAbs.png"))
sources=sources, resolution=resolution) # reflected flux refl = sim.add_flux(fcen, df, nfreq, refl_fr) tran_fr = mp.FluxRegion(center=mp.Vector3(0.5 * sx - dpml - 0.5, 4.0, 0), size=mp.Vector3(0.0, 2.0 * width, 0)) tran = sim.add_flux(fcen, df, nfreq, tran_fr) # for normal run, load negated fields to subtract incident from refl. fields sim.load_minus_flux_data(refl, straight_refl_data) pt = mp.Vector3(4.0, 0.5 * sx - dpml - 0.5) sim.run(mp.at_time(200, mp.output_efield_z), until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, pt, 1e-3)) bend_refl_flux = mp.get_fluxes(refl) bend_tran_flux = mp.get_fluxes(tran) flux_freqs = mp.get_flux_freqs(refl) wl = [] Rs = [] Ts = [] for i in range(0, nfreq): wl = np.append(wl, 1 / flux_freqs[i]) Rs = np.append(Rs, -bend_refl_flux[i] / straight_tran_flux[i]) Ts = np.append(Ts, bend_tran_flux[i] / straight_tran_flux[i])
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 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.GaussianSource( frequency = fcen, # fwidth = df), # size = mp.Vector3(0,H), # center = mp.Vector3(Ls, 0), # eig_parity = eig_parity) ] sources = [ mp.EigenModeSource(mp.ContinuousSource(frequency=fcen), size=mp.Vector3(0, monitorheight), 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 notchtest-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 # T = 50*(a-4)/12; T = 60 if resolution == 50: epsform = "eps-000000.00" else: epsform = "eps-000000000" if gif: # and w == 0.1: sim.use_output_directory() sim.run(mp.at_beginning(mp.output_epsilon), mp.at_every( 1, mp.output_png( mp.Ez, "-RZc bluered -A notchtest-out/notchtest-" + epsform + ".h5 -a gray:.2")), mp.at_end(get_refl_slice), mp.at_end(get_tran_slice), until=T) os.system("convert notchtest-out/notchtest-ez-*.png " + casedash + "-" + str(int(w * 1000)) + "-" + str(mode) + "-full.gif") os.system("rm notchtest-out/notchtest-ez-*.png") 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) # 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 notchtest-out/notchtest-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 notchtest-out/notchtest-" + epsform + ".h5 -a gray:.2")), until=19 * wavelength / 20) sim.run(until=20) # sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, mp.Vector3(), 1e-5)) else: sim.run(mp.at_beginning(mp.output_epsilon), mp.at_time(T, get_refl_slice), mp.at_time(T, get_tran_slice)) #, # until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, mp.Vector3(), 1e-5)) os.system("h5topng notchtest-out/notchtest-" + epsform + ".h5; mv notchtest-out/notchtest-" + epsform + ".png " + casedash + "-" + str(int(w * 1000)) + "-" + str(mode) + "-eps.png") # os.system("cp notchtest-out/notchtest-ez-000100.00.png " + case + "-" + str(int(w*1000)) + "-" + str(mode) + ".png") os.system("convert notchtest-out/notchtest-ez-*.png " + casedash + "-" + str(int(w * 1000)) + "-" + str(mode) + ".gif") os.system("rm notchtest-out/notchtest-ez-*.png") # 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 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_amp0 = fund_refl_amp fund_tran_amp0 = fund_tran_amp 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) f2.write( "%s, " % [fund_refl_amp0, fund_tran_amp0, fund_refl_amp, fund_tran_amp]) # assert(fund_refl_power + not_fund_refl_power == 1) # assert(fund_tran_power + not_fund_tran_power == 1) # f2.write("\n"); 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 f2.write("%s, " % [ fund_refl_ratio, fund_refl_power, not_fund_refl_power, fund_refl_power + not_fund_refl_power, fund_tran_ratio, fund_tran_power, not_fund_tran_power, fund_tran_power + not_fund_tran_power ]) 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, 'co-', label='over') plt.plot(y_list, not_fund_refl, 'ko-', 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.savefig(case + "fields.png") plt.close() # # 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) 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()