mp.Source(mp.GaussianSource(fcen, fwidth=df), mp.Hz, mp.Vector3()) ] # run until sources are finished (and no later) sim._run_sources_until(0, []) # get 1D and 2D array slices xMin = -0.25 * sx xMax = +0.25 * sx yMin = -0.15 * sy yMax = +0.15 * sy # 1D slice of Hz data size_1d = mp.Vector3(xMax - xMin) center_1d = mp.Vector3((xMin + xMax) / 2) slice1d = sim.get_array(vol=mp.Volume(center_1d, size=size_1d), component=mp.Hz) # 2D slice of Hz data size_2d = mp.Vector3(xMax - xMin, yMax - yMin) center_2d = mp.Vector3((xMin + xMax) / 2, (yMin + yMax) / 2) slice2d = sim.get_array(vol=mp.Volume(center_2d, size=size_2d), component=mp.Hz) # plot 1D slice plt.subplot(1, 2, 1) x1d = np.linspace(xMin, xMax, len(slice1d)) plt.plot(x1d, slice1d) # plot 2D slice plt.subplot(1, 2, 2)
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"))
class TestFieldFunctions(unittest.TestCase): cs = [mp.Ex, mp.Hz, mp.Dielectric] vol = mp.Volume(size=mp.Vector3(1), center=mp.Vector3()) def init(self): resolution = 20 cell = mp.Vector3(10, 10, 0) pml_layers = mp.PML(1.0) fcen = 1.0 df = 1.0 sources = mp.Source(src=mp.GaussianSource(fcen, fwidth=df), center=mp.Vector3(), component=mp.Ez) symmetries = [mp.Mirror(mp.X), mp.Mirror(mp.Y)] return mp.Simulation(resolution=resolution, cell_size=cell, boundary_layers=[pml_layers], sources=[sources], symmetries=symmetries) def init2(self): n = 3.4 w = 1 r = 1 pad = 4 dpml = 2 sxy = 2 * (r + w + pad + dpml) cell = mp.Vector3(sxy, sxy) geometry = [ mp.Cylinder(radius=r + w, height=mp.inf, material=mp.Medium(index=n)), mp.Cylinder(radius=r, height=mp.inf, material=mp.air) ] pml_layers = [mp.PML(dpml)] resolution = 5 fcen = 0.118 df = 0.010 sources = [ mp.Source(src=mp.GaussianSource(fcen, fwidth=df), component=mp.Ez, center=mp.Vector3(r + 0.1)) ] symmetries = [mp.Mirror(mp.Y)] return mp.Simulation(cell_size=cell, resolution=resolution, geometry=geometry, boundary_layers=pml_layers, sources=sources, symmetries=symmetries) def test_integrate_field_function(self): sim = self.init() sim.use_output_directory(temp_dir) sim.run(until=200) res1 = sim.integrate_field_function(self.cs, f) res2 = sim.integrate_field_function(self.cs, f, self.vol) self.assertAlmostEqual(res1, complex(-6.938893903907228e-18, 0.0)) self.assertAlmostEqual(res2, 0.0j) sim.output_field_function("weird-function", self.cs, f) def test_integrate2_field_function(self): sim = self.init2() sim.run(until_after_sources=10) fields2 = sim.fields sim.reset_meep() sim.run(until_after_sources=10) res1 = sim.integrate2_field_function(fields2, [mp.Ez], [mp.Ez], f2) self.assertAlmostEqual(res1, 0.17158099566244897) def test_max_abs_field_function(self): sim = self.init() sim.run(until=200) self.cs = [mp.Ex, mp.Hz, mp.Dielectric] res = sim.max_abs_field_function(self.cs, f, self.vol) self.assertAlmostEqual(res, 0.27593732304637586)
import meep as mp import numpy as np from numpy import linalg as LA import matplotlib.pyplot as plt n = 3.4 w = 1 r = 1 pad = 4 dpml = 2 sxy = 2 * (r + w + pad + dpml) vol = mp.Volume(mp.Vector3(), size=mp.Vector3(sxy - 2 * dpml, sxy - 2 * dpml)) c1 = mp.Cylinder(radius=r + w, material=mp.Medium(index=n)) c2 = mp.Cylinder(radius=r) fcen = 0.118 df = 0.08 src = mp.Source(mp.ContinuousSource(fcen, fwidth=df), mp.Ez, mp.Vector3(r + 0.1)) sim = mp.Simulation(cell_size=mp.Vector3(sxy, sxy), geometry=[c1, c2], sources=[src], resolution=10, force_complex_fields=True, symmetries=[mp.Mirror(mp.Y)], boundary_layers=[mp.PML(dpml)]) num_tols = 5
def test_animation_output(self): # ------------------------- # # Check over 2D domain # ------------------------- # sim = setup_sim() # generate 2D simulation Animate = mp.Animate2D(sim, fields=mp.Ez, realtime=False, normalize=False) # Check without normalization Animate_norm = mp.Animate2D(sim, mp.Ez, realtime=False, normalize=True) # Check with normalization # test both animation objects during same run sim.run(mp.at_every(1, Animate), mp.at_every(1, Animate_norm), until=5) # Test outputs Animate.to_mp4(5, os.path.join(temp_dir, 'test_2D.mp4')) # Check mp4 output Animate.to_gif(150, os.path.join(temp_dir, 'test_2D.gif')) # Check gif output Animate.to_jshtml(10) # Check jshtml output Animate_norm.to_mp4(5, os.path.join( temp_dir, 'test_2D_norm.mp4')) # Check mp4 output Animate_norm.to_gif(150, os.path.join( temp_dir, 'test_2D_norm.gif')) # Check gif output Animate_norm.to_jshtml(10) # Check jshtml output # ------------------------- # # Check over 3D domain # ------------------------- # sim = setup_sim(5) # generate 2D simulation Animate_xy = mp.Animate2D( sim, fields=mp.Ey, realtime=False, normalize=True) # Check without normalization Animate_xz = mp.Animate2D(sim, mp.Ey, realtime=False, normalize=True) # Check with normalization # test both animation objects during same run sim.run(mp.at_every( 1, mp.in_volume( mp.Volume(center=mp.Vector3(), size=mp.Vector3(sim.cell_size.x, sim.cell_size.y)), Animate_xy)), mp.at_every( 1, mp.in_volume( mp.Volume(center=mp.Vector3(), size=mp.Vector3(sim.cell_size.x, 0, sim.cell_size.z)), Animate_xz)), until=5) # Test outputs Animate_xy.to_mp4(5, os.path.join(temp_dir, 'test_3D_xy.mp4')) # Check mp4 output Animate_xy.to_gif(150, os.path.join(temp_dir, 'test_3D_xy.gif')) # Check gif output Animate_xy.to_jshtml(10) # Check jshtml output Animate_xz.to_mp4(5, os.path.join(temp_dir, 'test_3D_xz.mp4')) # Check mp4 output Animate_xz.to_gif(150, os.path.join(temp_dir, 'test_3D_xz.gif')) # Check gif output Animate_xz.to_jshtml(10) # Check jshtml output
eig_band=1, direction=mp.NO_DIRECTION, eig_kpoint=kpoint, size=source_size, eig_parity=mp.EVEN_Y, # TE mode center=source_center) ] #---------------------------------------------------------------------- #- geometric objects #---------------------------------------------------------------------- Nx = 10 Ny = 10 design_region = mp.Volume(center=mp.Vector3(), size=mp.Vector3(1, 1, 0)) rho_vector = 11 * np.random.rand(Nx * Ny) + 1 basis = mpa.BilinearInterpolationBasis(volume=design_region, Nx=Nx, Ny=Ny, rho_vector=rho_vector) geometry = [ mp.Block(center=mp.Vector3(x=-Sx / 4), material=mp.Medium(index=3.45), size=mp.Vector3(Sx / 2, 0.5, 0)), # horizontal waveguide mp.Block(center=mp.Vector3(), material=mp.Medium(index=3.45), size=mp.Vector3(0.5, mp.inf, 0)), # vertical waveguide mp.Block(center=design_region.center, size=design_region.size,
source_time_profile = mp.GaussianSource(fcen, fwidth=df) sources = [mp.Source(src=source_time_profile, component=mp.Ez, center=origin)] symmetries = [mp.Mirror(mp.Y)] if use_symmetry else [] pml_layers = [mp.PML(dpml)] sim = mp.Simulation(cell_size=cell, geometry=geometry, boundary_layers=pml_layers, sources=sources, symmetries=symmetries, resolution=resolution) # mv_box is the region within which we compute modal volume mv_box_size = mp.Vector3(L_inner, L_inner, mp.inf) mv_box = mp.Volume(center=origin, size=mv_box_size) dft_cell = sim.add_dft_fields([mp.Ex, mp.Ey, mp.Ez], fcen - df, fcen + df, 3, where=mv_box) # Timestep until the sources are finished, pausing at fixed intervals to # compare the modal volume within mv_box as computed from time-domain fields # (a) by the built-in mode-volume computation in libmeep, # (b) by the python routine above based on array metadata source_end_time = source_time_profile.swigobj.last_time_max() measurement_interval = source_end_time / 10.0 next_measurement_time = sim.round_time( ) + 2 * measurement_interval # skip first interval td_values = 0
def test_get_dft_array(self): sim = self.init() sim.init_sim() dft_fields = sim.add_dft_fields([mp.Ez], self.fcen, 0, 1) fr = mp.FluxRegion(mp.Vector3(), size=mp.Vector3(self.sxy, self.sxy), direction=mp.X) dft_flux = sim.add_flux(self.fcen, 0, 1, fr) # volumes with zero thickness in x and y directions to test collapsing # of empty dimensions in DFT array and HDF5 output routines thin_x_volume = mp.Volume(center=mp.Vector3(0.35 * self.sxy), size=mp.Vector3(y=0.8 * self.sxy)) thin_x_flux = sim.add_dft_fields([mp.Ez], self.fcen, 0, 1, where=thin_x_volume) thin_y_volume = mp.Volume(center=mp.Vector3(y=0.25 * self.sxy), size=mp.Vector3(x=self.sxy)) thin_y_flux = sim.add_flux(self.fcen, 0, 1, mp.FluxRegion(volume=thin_y_volume)) sim.run(until_after_sources=100) # test proper collapsing of degenerate dimensions in HDF5 files and arrays thin_x_array = sim.get_dft_array(thin_x_flux, mp.Ez, 0) thin_y_array = sim.get_dft_array(thin_y_flux, mp.Ez, 0) np.testing.assert_equal(thin_x_array.ndim, 1) np.testing.assert_equal(thin_y_array.ndim, 1) sim.output_dft(thin_x_flux, os.path.join(self.temp_dir, 'thin-x-flux')) sim.output_dft(thin_y_flux, os.path.join(self.temp_dir, 'thin-y-flux')) with h5py.File(os.path.join(self.temp_dir, 'thin-x-flux.h5'), 'r') as thin_x: thin_x_h5 = mp.complexarray(thin_x['ez_0.r'][()], thin_x['ez_0.i'][()]) with h5py.File(os.path.join(self.temp_dir, 'thin-y-flux.h5'), 'r') as thin_y: thin_y_h5 = mp.complexarray(thin_y['ez_0.r'][()], thin_y['ez_0.i'][()]) tol = 1e-6 self.assertClose(thin_x_array, thin_x_h5, epsilon=tol) self.assertClose(thin_y_array, thin_y_h5, epsilon=tol) # compare array data to HDF5 file content for fields and flux fields_arr = sim.get_dft_array(dft_fields, mp.Ez, 0) flux_arr = sim.get_dft_array(dft_flux, mp.Ez, 0) sim.output_dft(dft_fields, os.path.join(self.temp_dir, 'dft-fields')) sim.output_dft(dft_flux, os.path.join(self.temp_dir, 'dft-flux')) with h5py.File(os.path.join(self.temp_dir, 'dft-fields.h5'), 'r') as fields, h5py.File( os.path.join(self.temp_dir, 'dft-flux.h5'), 'r') as flux: exp_fields = mp.complexarray(fields['ez_0.r'][()], fields['ez_0.i'][()]) exp_flux = mp.complexarray(flux['ez_0.r'][()], flux['ez_0.i'][()]) tol = 1e-6 self.assertClose(exp_fields, fields_arr, epsilon=tol) self.assertClose(exp_flux, flux_arr, epsilon=tol)
mp.Source(mp.GaussianSource(fcen, fwidth=df), mp.Hz, mp.Vector3()) ] # run until sources are finished (and no later) sim._run_sources_until(0, []) # get 1D and 2D array slices xMin = -0.25 * sx xMax = +0.25 * sx yMin = -0.15 * sy yMax = +0.15 * sy # 1D slice of Hz data size_1d = mp.Vector3(xMax - xMin) center_1d = mp.Vector3((xMin + xMax) / 2) slice1d = sim.get_array(mp.Volume(center_1d, size=size_1d), component=mp.Hz) # 2D slice of Hz data size_2d = mp.Vector3(xMax - xMin, yMax - yMin) center_2d = mp.Vector3((xMin + xMax) / 2, (yMin + yMax) / 2) slice2d = sim.get_array(mp.Volume(center_2d, size=size_2d), component=mp.Hz) # plot 1D slice plt.subplot(1, 2, 1) x1d = np.linspace(xMin, xMax, len(slice1d)) plt.plot(x1d, slice1d) # plot 2D slice plt.subplot(1, 2, 2) dy = (yMax - yMin) / slice2d.shape[1] dx = (xMax - xMin) / slice2d.shape[0]
rot_angle = 0 # CCW rotation angle about z axis (0: +y axis) beam_kdir = mp.Vector3(0, 1, 0).rotate(mp.Vector3( 0, 0, 1), math.radians(rot_angle)) # beam propagation direction beam_w0 = 0.8 # beam waist radius beam_E0 = mp.Vector3(0, 0, 1) fcen = 1 sources = [ mp.GaussianBeamSource(src=mp.ContinuousSource(fcen), center=mp.Vector3(0, -0.5 * s + dpml + 1.0), size=mp.Vector3(s), beam_x0=beam_x0, beam_kdir=beam_kdir, beam_w0=beam_w0, beam_E0=beam_E0) ] sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=boundary_layers, sources=sources) sim.run(until=20) sim.plot2D(fields=mp.Ez, output_plane=mp.Volume(center=mp.Vector3(), size=mp.Vector3(s - 2 * dpml, s - 2 * dpml))) plt.savefig('Ez_angle{}.png'.format(rot_angle), bbox_inches='tight', pad_inches=0)
def _get_waveguide_mode(sim: mp.Simulation, src: WaveguideModeSource) -> MeepWaveguideMode: """Computes the waveguide mode in Meep (via MPB). Args: sim: Meep simulation object. src: Waveguide mode source properties. Returns: A tuple `(mode_fields, mode_comps, xyzw)`. `mode_fields` is the sampled transverse fields of the mode. `mode_fields` is an array with four elements, one for each transverse element as determined by `mode_comps`. `xyzw` is the Meep array metadata for the region: It is a 4-element tuple `(x, y, z, w)` where the `x`, `y`, and `z` are arrays indicating the cell coordinates where the fields are sampled and `w` is the volume weight factor used when calculating integrals involving the fields (see Meep documentation for details). """ wlen = src.wavelength fcen = 1 / wlen normal_axis = gridlock.axisvec2axis(src.normal) # Extract the eigenmode from Meep. # `xyzw` is a tuple `(x_coords, y_coords, z_coords, weights)` where # `x_coords`, `y_coords`, and `z_coords` is a list of the coordinates of # the Yee cells within the source region. # TODO(logansu): Remove this hack when Meep fixes its bugs with # `get_array_metadata`. For now, we ensure that the slices are 3D, otherwise # the values returned for `w` can be wrong and undeterministic. dx = 1 / sim.resolution # Count number of dimensions are effectively "zero". This is used to # determine the dimensionality of the source (1D or 2D). overlap_dims = 3 - sum(val <= dx for val in src.extents) extents = [val if val >= dx else dx for val in src.extents] xyzw = sim.get_array_metadata(center=src.center, size=extents) # TODO(logansu): Understand how to guess a k-vector. Is it necessary? k_guess = [0, 0, 0] k_guess[normal_axis] = fcen k_guess = mp.Vector3(*k_guess) mode_dirs = [mp.X, mp.Y, mp.Z] mode_data = sim.get_eigenmode( fcen, mode_dirs[normal_axis], mp.Volume(center=src.center, size=src.extents), src.mode_num + 1, k_guess) # Determine which field components are relevant for TFSF source (i.e. the # field components tangential to the propagation direction. # For simplicity, we order them in circular permutation order (x->y->z) with # E fields followed by H fields. if normal_axis == 0: field_comps = [mp.Ey, mp.Ez, mp.Hy, mp.Hz] elif normal_axis == 1: field_comps = [mp.Ez, mp.Ex, mp.Hz, mp.Hx] else: field_comps = [mp.Ex, mp.Ey, mp.Hx, mp.Hy] # Extract the actual field values for the relevant field components. # Note that passing in `mode_data.amplitude` into `amp_func` parameter of # `mp.Source` seems to give a bad source. mode_fields = [] for c in field_comps: field_slice = [] for x, y, z in itertools.product(xyzw[0], xyzw[1], xyzw[2]): field_slice.append(mode_data.amplitude(mp.Vector3(x, y, z), c)) field_slice = np.reshape(field_slice, (len(xyzw[0]), len(xyzw[1]), len(xyzw[2]))) mode_fields.append(field_slice) # Sometimes Meep returns an extra layer of fields when one of the dimensions # of the overlap region is zero. In that case, only use the first slice. field_slicer = [slice(None), slice(None), slice(None)] field_slicer[normal_axis] = slice(0, 1) field_slicer = tuple(field_slicer) for i in range(4): mode_fields[i] = mode_fields[i][field_slicer] xyzw[3] = np.reshape(xyzw[3], (len(xyzw[0]), len(xyzw[1]), len(xyzw[2]))) xyzw[3] = xyzw[3][field_slicer] # TODO(logansu): See above TODO about hacking `get_array_metadata`. # For now, just guess the correct value. The error introduced by this # occurs at the edges of the source/overlap where the fields are small # anyway. xyzw[3][:] = dx**overlap_dims # Fix the phase of the mode by normalizing the phase by the phase where # the electric field as largest magnitude. arr = np.hstack([mode_fields[0].flatten(), mode_fields[1].flatten()]) phase_norm = np.angle(arr[np.argmax(np.abs(arr))]) phase_norm = np.exp(1j * phase_norm) mode_fields = [f / phase_norm for f in mode_fields] return MeepWaveguideMode(wlen, field_comps, mode_fields, xyzw)
def get_arr2(sim): eps['arr2'] = sim.get_array(mp.Volume(mp.Vector3(), mp.Vector3(10, 10)), component=mp.Dielectric)
def volume(self): return mp.Volume(center=self.center, size=self.size)
d1 = 0.2 sim = mp.Simulation(cell_size=cell, geometry=geometry, sources=[sources], symmetries=symmetries, boundary_layers=[pml_layers], resolution=resolution) nearfield = sim.add_near2far( fcen, 0, 1, mp.Near2FarRegion(mp.Vector3(0, 0.5 * w + d1), size=mp.Vector3(2 * dpml - sx)), mp.Near2FarRegion(mp.Vector3(-0.5 * sx + dpml, 0.5 * w + 0.5 * d1), size=mp.Vector3(0, d1), weight=-1.0), mp.Near2FarRegion(mp.Vector3(0.5 * sx - dpml, 0.5 * w + 0.5 * d1), size=mp.Vector3(0, d1))) sim.run(until_after_sources=mp.stop_when_fields_decayed( 50, mp.Hz, mp.Vector3(0.12, -0.37), 1e-8)) d2 = 20 h = 4 sim.output_farfields( nearfield, "spectra-{}-{}-{}".format(d1, d2, h), mp.Volume(mp.Vector3(0, (0.5 * w) + d2 + (0.5 * h)), size=mp.Vector3(sx - 2 * dpml, h)), resolution)
] sim = mp.Simulation(cell_size=cell_size, resolution=resolution, boundary_layers=pml_layers, sources=sources, geometry=geometry, symmetries=[mp.Mirror(mp.Y)] if rot_angle == 0 else []) if compute_flux: 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) print("flux:, {:.6f}".format(mp.get_fluxes(tran)[0])) else: sim.run(until=100) nonpml_vol = mp.Volume(center=mp.Vector3(), size=mp.Vector3(10, 10, 0)) eps_data = sim.get_array(vol=nonpml_vol, component=mp.Dielectric) ez_data = sim.get_array(vol=nonpml_vol, component=mp.Ez) plt.figure() plt.imshow(np.flipud(np.transpose(eps_data)), interpolation='spline36', cmap='binary') plt.imshow(np.flipud(np.transpose(ez_data)), interpolation='spline36', cmap='RdBu', alpha=0.9) plt.axis('off') plt.show()
def adjoint_solver(design_params, mon_type, frequencies=None, mat2=silicon): matgrid = mp.MaterialGrid(mp.Vector3(Nx, Ny), mp.air, mat2, weights=np.ones((Nx, Ny))) matgrid_region = mpa.DesignRegion( matgrid, volume=mp.Volume(center=mp.Vector3(), size=mp.Vector3(design_region_size.x, design_region_size.y, 0))) matgrid_geometry = [ mp.Block(center=matgrid_region.center, size=matgrid_region.size, material=matgrid) ] geometry = waveguide_geometry + matgrid_geometry sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=pml_xy, sources=wvg_source, geometry=geometry) if not frequencies: frequencies = [fcen] if mon_type.name == 'EIGENMODE': obj_list = [ mpa.EigenmodeCoefficient( sim, mp.Volume(center=mp.Vector3(0.5 * sxy - dpml - 0.1), size=mp.Vector3(0, sxy - 2 * dpml, 0)), 1, eig_parity=eig_parity) ] def J(mode_mon): return npa.power(npa.abs(mode_mon), 2) elif mon_type.name == 'DFT': obj_list = [ mpa.FourierFields( sim, mp.Volume(center=mp.Vector3(1.25), size=mp.Vector3(0.25, 1, 0)), mp.Ez) ] def J(mode_mon): return npa.power(npa.abs(mode_mon[:, 4, 10]), 2) opt = mpa.OptimizationProblem(simulation=sim, objective_functions=J, objective_arguments=obj_list, design_regions=[matgrid_region], frequencies=frequencies) f, dJ_du = opt([design_params]) sim.reset_meep() return f, dJ_du
symmetries = [mp.Mirror(mp.Y, phase=-1), mp.Mirror(mp.X, phase=-1)] d1 = 0.2 sim = mp.Simulation(cell_size=cell, geometry=geometry, sources=[sources], symmetries=symmetries, boundary_layers=[pml_layers], resolution=resolution) nearfield = sim.add_near2far( fcen, 0, 1, mp.Near2FarRegion(mp.Vector3(0, 0.5 * w + d1), size=mp.Vector3(2 * dpml - sx)), mp.Near2FarRegion(mp.Vector3(-0.5 * sx + dpml, 0.5 * w + 0.5 * d1), size=mp.Vector3(0, d1), weight=-1.0), mp.Near2FarRegion(mp.Vector3(0.5 * sx - dpml, 0.5 * w + 0.5 * d1), size=mp.Vector3(0, d1)) ) sim.run(until_after_sources=mp.stop_when_fields_decayed( 50, mp.Hz, mp.Vector3(0.12, -0.37), 1e-8)) d2 = 20 h = 4 sim.output_farfields(nearfield, "spectra-{}-{}-{}".format(d1, d2, h), resolution, where=mp.Volume(mp.Vector3(0, (0.5 * w) + d2 + (0.5 * h)), size=mp.Vector3(sx - 2 * dpml, h)))
component=mp.Ez) ] sim = mp.Simulation(cell_size=cell_size, resolution=resolution, boundary_layers=pml_layers, sources=sources, geometry=geometry, symmetries=[mp.Mirror(mp.Y)] if rot_angle == 0 else []) if compute_flux: 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], eig_parity=mp.EVEN_Y + mp.ODD_Z if rot_angle == 0 else mp.ODD_Z, direction=mp.NO_DIRECTION, kpoint_func=lambda f, n: kpoint) print("flux:, {:.6f}, {:.6f}".format( mp.get_fluxes(tran)[0], abs(res.alpha[0, 0, 0])**2)) else: sim.run(until=100) sim.plot2D(output_plane=mp.Volume(center=mp.Vector3(), size=mp.Vector3(10, 10)), fields=mp.Ez, field_parameters={'alpha': 0.9}) plt.show()
mp.FluxRegion(center=mp.Vector3(+0.5 * sxy, 0), size=mp.Vector3(0, sxy), weight=+1), mp.FluxRegion(center=mp.Vector3(-0.5 * sxy, 0), size=mp.Vector3(0, 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(
sx = 14 * rad # Size of inner shell sy = 14 * rad # Size of inner shell sx0 = sx + 2 * dpml # size of cell in X direction sy0 = sy + 2 * dpml # size of cell in Y direction mx = 8 * rad fx = 4 * rad sc = 6 * rad # source center coordinate shift sw = sx0 # source width, needs to be bigger than inner cell to generate only plane-waves nfreq = 100 # number of frequencies at which to compute flux courant = 0.5 # numerical stability, default is 0.5, should be lower in case refractive index n<1 time_step = 0.05 # time step to measure flux add_time = 2 # additional time until field decays 1e-6 resolution = 2500 # resolution pixels/um (pixels/micrometers) decay = 1e-12 # decay limit condition for the field measurement cell = mp.Vector3(sx0, sy0, 0) monitor = mp.Volume(center=mp.Vector3(0, 0, 0), size=mp.Vector3(mx, mx, 0)) ''' +--------------------Cell-------------------+ | | | PML | | +-------------------------------+ | | | | | | | .pt | | | | | | | | +---+monitor-area---+ | | | | | | | | | | | +---Flux----+ | | | | | | | | | | | | | | | XXX | | | | | | | | XXXXX | | | |
def Simulation(period, grating_t, grating_w, sep, mthick, mat): #----------------------Variables------------------------------ sub = 1.4 #thickness of the substrate (where the grating is embedded) d1 = 1.52 #dielectric constant of medium dpml = 0.2 #um air = 1.5 #um matty = [Au, Ag] #-------------------------Clear------------------------------- #if os.path.exists("dft_X_empty.h5"): # os.remove("dft_X_empty.h5") #if os.path.exists("dft_X_fields.h5"): # os.remove("dft_X_fields.h5") #if os.path.exists("dft_Y_empty.h5"): # os.remove("dft_Y_empty.h5") #if os.path.exists("dft_Y_fields.h5"): # os.remove("dft_Y_fields.h5") #----------------------Simulation------------------------------ ideal = np.loadtxt('ideal_peak.txt') # maximum source waveWIDTH lambda_ideal = ideal nfreq = 1 f_cen = 1 / lambda_ideal # source frequency center df = 0.05 * f_cen # source frequency width sy = period sx = dpml + sub + sep + mthick + air + dpml resolution = 1000 #pixels/um diel1 = mp.Medium(index=d1) cell = mp.Vector3(sx, sy, 0) #define Gaussian plane wave sources = [ mp.Source(mp.GaussianSource(f_cen, fwidth=df), component=mp.Hz, center=mp.Vector3(-0.5 * sx + dpml + 0.1, 0, 0), size=mp.Vector3(0, sy, 0)) ] #define pml layers pml_layers = [mp.Absorber(thickness=dpml, direction=mp.X)] supers = mp.Block(mp.Vector3(sub + sep, mp.inf, mp.inf), center=mp.Vector3(-0.5 * sx + 0.5 * (sub + sep), 0, 0), material=diel1) geometry = [supers] #mp.quiet(quietval=True) sim = mp.Simulation(cell_size=cell, boundary_layers=pml_layers, sources=sources, symmetries=[mp.Mirror(mp.Y, phase=-1)], dimensions=2, resolution=resolution, k_point=mp.Vector3(0, 0, 0)) #----------------------Monitors------------------------------ dfts_Y1 = sim.add_dft_fields([mp.Ey], f_cen, f_cen, 1, where=mp.Volume(center=mp.Vector3( 0.5 * sx - dpml - 0.5 * (mthick + air), 0), size=mp.Vector3( air + mthick, sy))) dfts_X1 = sim.add_dft_fields([mp.Ex], f_cen, f_cen, 1, where=mp.Volume(center=mp.Vector3( 0.5 * sx - dpml - 0.5 * (mthick + air), 0), size=mp.Vector3( air + mthick, sy))) #----------------------Run------------------------------ sim.run(until_after_sources=100) #----------------------Reset------------------------------ sim.output_dft(dfts_Y1, "dft_Y_empty") sim.output_dft(dfts_X1, "dft_X_empty") sim.reset_meep() grating = mp.Block(mp.Vector3(grating_t, grating_w, mp.inf), center=mp.Vector3(-0.5 * sx + sub - 0.5 * grating_t, 0, 0), material=matty[int(mat)]) metal = mp.Block(mp.Vector3(mthick, mp.inf, mp.inf), center=mp.Vector3(-0.5 * sx + sub + sep + 0.5 * mthick, 0, 0), material=matty[int(mat)]) geometry = [supers, grating, metal] sim = mp.Simulation(cell_size=cell, boundary_layers=pml_layers, sources=sources, geometry=geometry, symmetries=[mp.Mirror(mp.Y, phase=-1)], dimensions=2, resolution=resolution, k_point=mp.Vector3(0, 0, 0)) dfts_Y2 = sim.add_dft_fields([mp.Ey], f_cen, f_cen, 1, where=mp.Volume(center=mp.Vector3( 0.5 * sx - dpml - 0.5 * (mthick + air), 0), size=mp.Vector3( air + mthick, sy))) dfts_X2 = sim.add_dft_fields([mp.Ex], f_cen, f_cen, 1, where=mp.Volume(center=mp.Vector3( 0.5 * sx - dpml - 0.5 * (mthick + air), 0), size=mp.Vector3( air + mthick, sy))) sim.run(until_after_sources=400) #mp.at_beginning(mp.output_epsilon), sim.output_dft(dfts_Y2, "dft_Y_fields") sim.output_dft(dfts_X2, "dft_X_fields") #----------------------------Graph the Outputs---------------------------- with h5py.File('dft_Y_fields.h5', 'r') as Esy: with h5py.File('dft_Y_empty.h5', 'r') as Eoy: with h5py.File('dft_X_fields.h5', 'r') as Esx: with h5py.File('dft_X_empty.h5', 'r') as Eox: eix2 = np.array(Esx[('ex_0.i')]) erx2 = np.array(Esx[('ex_0.r')]) eiy2 = np.array(Esy[('ey_0.i')]) ery2 = np.array(Esy[('ey_0.r')]) E2 = (eix2**2 + erx2**2) + (eiy2**2 + ery2**2) eix2 = np.array(Eox[('ex_0.i')]) erx2 = np.array(Eox[('ex_0.r')]) eiy2 = np.array(Eoy[('ey_0.i')]) ery2 = np.array(Eoy[('ey_0.r')]) E1 = (eix2**2 + erx2**2) + (eiy2**2 + ery2**2) Enhance = E2 / E1 Enhance = np.rot90(Enhance) heat_map = sb.heatmap(Enhance, cmap='plasma', xticklabels=False, yticklabels=False) plt.ylabel("y-axis") plt.xlabel("x-axis") plt.savefig('Enhance_Z.png') en = np.zeros(len(Enhance[0])) pos = np.linspace(0, 3.82, len(en)) for i in range(len(Enhance[0])): en[i] = np.max(Enhance[:, i]) plt.clf() plt.figure() plt.plot(pos, en) plt.xlabel('position along substrate (um)') plt.ylabel('enhancement') plt.savefig('Profile.png') return ()
def plot_xsection(sim, center=(0, 0, 0), size=(0, 2, 2)): """ sim: simulation object """ sim.plot2D(output_plane=mp.Volume(center=center, size=size))
def init_problem(self, args): #---------------------------------------- # size of computational cell #---------------------------------------- lcen = 1.0 / args.fcen dpml = 0.5 * lcen if args.dpml == -1.0 else args.dpml dair = 0.5 * args.w_in if args.dair == -1.0 else args.dair sx = dpml + args.l_stub + args.l_design + args.l_stub + dpml sy = dpml + dair + args.h_design + dair + dpml cell_size = mp.Vector3(sx, sy, 0.0) #---------------------------------------- #- design region #---------------------------------------- design_center = origin design_size = mp.Vector3(args.l_design, args.h_design, 0.0) design_region = mp.Volume(center=design_center, size=design_size) #---------------------------------------- #- objective regions #---------------------------------------- x_in = -0.5 * (args.l_design + args.l_stub) x_out = +0.5 * (args.l_design + args.l_stub) y_out1 = +0.25 * args.h_design y_out2 = -0.25 * args.h_design flux_in = FluxLine(x_in, 0.0, 2.0 * args.w_in, mp.X, 'in') flux_out1 = FluxLine(x_out, y_out1, 2.0 * args.w_out1, mp.X, 'out1') flux_out2 = FluxLine(x_out, y_out2, 2.0 * args.w_out2, mp.X, 'out2') objective_regions = [flux_in, flux_out1, flux_out2] #---------------------------------------- #- optional extra regions for visualization if the --full-dfts options is present. #---------------------------------------- extra_regions = [mp.Volume(center=origin, size=cell_size) ] if args.full_dfts else [] #---------------------------------------- # forward source region #---------------------------------------- source_center = (x_in - 0.25 * args.l_stub) * xHat source_size = 2.0 * args.w_in * yHat #---------------------------------------- # basis set #---------------------------------------- basis = FiniteElementBasis(args.l_design, args.h_design, args.nfe) #---------------------------------------- #- objective function #---------------------------------------- fstr = ('Abs(P1_out1)**2' + '+0.0*(P1_out1 + M1_out1)' + '+0.0*(P1_out2 + M1_out2)' + '+0.0*(P1_in + M1_in + S_out1 + S_out2 + S_in)') #---------------------------------------- #- internal storage for variables needed later #---------------------------------------- self.args = args self.dpml = dpml self.cell_size = cell_size self.basis = basis self.design_center = origin self.design_size = design_size self.source_center = source_center self.source_size = source_size return fstr, objective_regions, extra_regions, design_region, basis
def test_farfield(self): resolution = 50 sxy = 4 dpml = 1 cell = mp.Vector3(sxy + 2 * dpml, sxy + 2 * dpml) 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(E[:, 1] * H[:, 2] - E[:, 2] * H[:, 1]) Py = np.real(E[:, 2] * H[:, 0] - 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 main(args): # Some parameters to describe the geometry: eps = 13 # dielectric constant of waveguide w = 1.2 # width of waveguide r = 0.36 # radius of holes d = 1.4 # defect spacing (ordinary spacing = 1) N = args.N # number of holes on either side of defect # The cell dimensions sy = args.sy # size of cell in y direction (perpendicular to wvg.) pad = 2 # padding between last hole and PML edge dpml = 1 # PML thickness sx = 2 * (pad + dpml + N) + d - 1 # size of cell in x direction cell = mp.Vector3(sx, sy, 0) blk = mp.Block(size=mp.Vector3(mp.inf, w, mp.inf), material=mp.Medium(epsilon=eps)) geometry = [blk] for i in range(N): geometry.append(mp.Cylinder(r, center=mp.Vector3(d / 2 + i))) geometry.append(mp.Cylinder(r, center=mp.Vector3(-(d / 2 + i)))) fcen = args.fcen # pulse center frequency df = args.df # pulse frequency width nfreq = 500 # number of frequencies at which to compute flux sim = mp.Simulation(cell_size=cell, geometry=geometry, sources=[], boundary_layers=[mp.PML(dpml)], resolution=20) if args.resonant_modes: sim.sources.append( mp.Source(mp.GaussianSource(fcen, fwidth=df), mp.Hz, mp.Vector3())) sim.symmetries.append(mp.Mirror(mp.Y, phase=-1)) sim.symmetries.append(mp.Mirror(mp.X, phase=-1)) sim.run( # mp.at_beginning(mp.output_epsilon), mp.after_sources(mp.Harminv(mp.Hz, mp.Vector3(), fcen, df)), until_after_sources=400) # sim.run(mp.at_every(1 / fcen / 20, mp.output_hfield_z), until=1 / fcen) else: sim.sources.append( mp.Source(mp.GaussianSource(fcen, fwidth=df), mp.Ey, mp.Vector3(dpml + (-0.5 * sx)), size=mp.Vector3(0, w))) sim.symmetries.append(mp.Mirror(mp.Y, phase=-1)) freg = mp.FluxRegion(center=mp.Vector3((0.5 * sx) - dpml - 0.5), size=mp.Vector3(0, 2 * w)) # transmitted flux trans = sim.add_flux(fcen, df, nfreq, freg) vol = mp.Volume(mp.Vector3(), size=mp.Vector3(sx)) sim.run(mp.at_beginning(mp.output_epsilon), mp.during_sources( mp.in_volume( vol, mp.to_appended("hz-slice", mp.at_every(0.4, mp.output_hfield_z)))), until_after_sources=mp.stop_when_fields_decayed( 50, mp.Ey, mp.Vector3((0.5 * sx) - dpml - 0.5, 0), 1e-3)) sim.display_fluxes(trans) # print out the flux spectrum
pml_layers = [mp.PML(1.0)] force_complex_fields = True # so we can get time-average flux resolution = 10 sim = mp.Simulation(cell_size=cell, geometry=geometry, sources=sources, boundary_layers=pml_layers, force_complex_fields=force_complex_fields, resolution=resolution) sim.run(mp.at_beginning(mp.output_epsilon), mp.at_end( mp.output_png(mp.Ez, "-a yarg -A $EPS -S3 -Zc dkbluered", rm_h5=False)), until=200) flux1 = sim.flux_in_box( mp.X, mp.Volume(center=mp.Vector3(-6.0), size=mp.Vector3(1.8, 6))) flux2 = sim.flux_in_box( mp.X, mp.Volume(center=mp.Vector3(6.0), size=mp.Vector3(1.8, 6))) # averaged over y region of width 1.8 print("left-going flux = {}".format(flux1 / -1.8)) # averaged over y region of width 1.8 print("right-going flux = {}".format(flux2 / 1.8))
sources = [ mp.Source(src=mp.ContinuousSource(fcen, fwidth=0.2 * fcen, start_time=10, end_time=15), component=mp.Ez, center=src_center, size=mp.Vector3(cell_size.x, cell_size.y), amp_func=gaussian_beam(sigma, k, src_center)) ] sim = mp.Simulation(cell_size=cell_size, sources=sources, boundary_layers=pml_layers, resolution=resolution) sim.run(until=20) x_plane = mp.Volume(center=mp.Vector3(0, 0, 0), size=mp.Vector3(0, cell_size.y, cell_size.x)) ez_x = sim.get_array(vol=x_plane, component=mp.Ez) print(sim.get_array(mp.Ez).max()) plt.figure() plt.imshow(np.flipud(np.transpose(np.real(ez_x))), interpolation='spline36', cmap='RdBu') plt.axis('off') plt.show()
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"))
def test_in_volume(self): sim = self.init_simple_simulation() sim.filename_prefix = 'test_in_volume' vol = mp.Volume(mp.Vector3(), size=mp.Vector3(x=2)) sim.run(mp.at_end(mp.in_volume(vol, mp.output_efield_z)), until=200)
def test_array_metadata(self): resolution = 25 n = 3.4 w = 1 r = 1 pad = 4 dpml = 2 sxy = 2*(r+w+pad+dpml) cell_size = mp.Vector3(sxy,sxy) nonpml_vol = mp.Volume(mp.Vector3(), size=mp.Vector3(sxy-2*dpml,sxy-2*dpml)) geometry = [mp.Cylinder(radius=r+w, material=mp.Medium(index=n)), mp.Cylinder(radius=r)] fcen = 0.118 df = 0.08 symmetries = [mp.Mirror(mp.X,phase=-1), mp.Mirror(mp.Y,phase=+1)] pml_layers = [mp.PML(dpml)] # CW source src = [mp.Source(mp.ContinuousSource(fcen,fwidth=df), mp.Ez, mp.Vector3(r+0.1)), mp.Source(mp.ContinuousSource(fcen,fwidth=df), mp.Ez, mp.Vector3(-(r+0.1)), amplitude=-1)] sim = mp.Simulation(cell_size=cell_size, geometry=geometry, sources=src, resolution=resolution, force_complex_fields=True, symmetries=symmetries, boundary_layers=pml_layers) sim.init_sim() sim.solve_cw(1e-6, 1000, 10) def electric_energy(r, ez, eps): return np.real(eps * np.conj(ez)*ez) def vec_func(r): return r.x**2 + 2*r.y**2 electric_energy_total = sim.integrate_field_function([mp.Ez,mp.Dielectric],electric_energy,nonpml_vol) electric_energy_max = sim.max_abs_field_function([mp.Ez,mp.Dielectric],electric_energy,nonpml_vol) vec_func_total = sim.integrate_field_function([],vec_func,nonpml_vol) cw_modal_volume = (electric_energy_total / electric_energy_max) * vec_func_total sim.reset_meep() # pulsed source src = [mp.Source(mp.GaussianSource(fcen,fwidth=df), mp.Ez, mp.Vector3(r+0.1)), mp.Source(mp.GaussianSource(fcen,fwidth=df), mp.Ez, mp.Vector3(-(r+0.1)), amplitude=-1)] sim = mp.Simulation(cell_size=cell_size, geometry=geometry, k_point=mp.Vector3(), sources=src, resolution=resolution, symmetries=symmetries, boundary_layers=pml_layers) dft_obj = sim.add_dft_fields([mp.Ez], fcen, 0, 1, where=nonpml_vol) sim.run(until_after_sources=100) Ez = sim.get_dft_array(dft_obj, mp.Ez, 0) (X,Y,Z,W) = sim.get_array_metadata(dft_cell=dft_obj) Eps = sim.get_array(vol=nonpml_vol,component=mp.Dielectric) EpsE2 = np.real(Eps*np.conj(Ez)*Ez) xm, ym = np.meshgrid(X,Y) vec_func_sum = np.sum(W*(xm**2 + 2*ym**2)) pulse_modal_volume = np.sum(W*EpsE2)/np.max(EpsE2) * vec_func_sum self.assertAlmostEqual(cw_modal_volume/pulse_modal_volume, 1.00, places=2)