From ccd87981531645b6f063b1db8595fe220196acbf Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Tue, 29 Mar 2022 04:46:06 +0000 Subject: [PATCH 1/4] Meep script to compute transmittance of metagrating imported from CSV file --- Metagrating3D/metagrating-meep.py | 151 ++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 Metagrating3D/metagrating-meep.py diff --git a/Metagrating3D/metagrating-meep.py b/Metagrating3D/metagrating-meep.py new file mode 100644 index 0000000..2bb17ca --- /dev/null +++ b/Metagrating3D/metagrating-meep.py @@ -0,0 +1,151 @@ +# compute the transmittance of the m=+1 order +# for a 3d metagrating with the 2d design +# imported from the file device1.csv +# and compare the result with the expected value +# from RCWA (Reticolo) + +import meep as mp +import math +import numpy as np +import matplotlib +matplotlib.use('agg') +import matplotlib.pyplot as plt + + +def metagrating(P_pol: bool): + resolution = 50 # pixels/μm + + nSi = 3.45 + Si = mp.Medium(index=nSi) + nSiO2 = 1.45 + SiO2 = mp.Medium(index=nSiO2) + + theta_d = math.radians(50.0) # deflection angle + + wvl = 1.05 # wavelength + fcen = 1/wvl + + px = wvl/math.sin(theta_d) # period in x + py = 0.5*wvl # period in y + + dpml = wvl # PML thickness + gh = 0.325 # grating height + dsub = 3.0 # substrate thickness + dair = 3.0 # air padding + + sz = dpml+dsub+gh+dair+dpml + + cell_size = mp.Vector3(px,py,sz) + + boundary_layers = [mp.PML(thickness=dpml,direction=mp.Z)] + + # periodic boundary conditions + k_point = mp.Vector3() + + ## disabled due to https://github.com/NanoComp/meep/issues/132 + # symmetries = [mp.Mirror(direction=mp.Y)] + + # plane of incidence is XZ + # P/TM polarization: Ex, S/TE polarization: Ey + src_cmpt = mp.Ex if P_pol else mp.Ey + sources = [mp.Source(src=mp.GaussianSource(fcen,fwidth=0.2*fcen), + size=mp.Vector3(px,py,0), + center=mp.Vector3(0,0,-0.5*sz+dpml), + component=src_cmpt)] + + sim = mp.Simulation(resolution=resolution, + cell_size=cell_size, + sources=sources, + default_material=SiO2, + boundary_layers=boundary_layers, + k_point=k_point) + + flux = sim.add_mode_monitor(fcen, + 0, + 1, + mp.ModeRegion(center=mp.Vector3(0,0,0.5*sz-dpml), + size=mp.Vector3(px,py,0))) + + sim.run(until_after_sources=mp.stop_when_dft_decayed()) + + input_flux = mp.get_fluxes(flux) + + sim.reset_meep() + + weights = np.genfromtxt('device1.csv',delimiter=',') + Nx, Ny = weights.shape + + geometry = [mp.Block(size=mp.Vector3(mp.inf,mp.inf,dpml+dsub), + center=mp.Vector3(0,0,-0.5*sz+0.5*(dpml+dsub)), + material=SiO2), + mp.Block(size=mp.Vector3(px,py,gh), + center=mp.Vector3(0,0,-0.5*sz+dpml+dsub+0.5*gh), + material=mp.MaterialGrid(grid_size=mp.Vector3(Nx,Ny,1), + medium1=mp.air, + medium2=Si, + weights=weights))] + + sim = mp.Simulation(resolution=resolution, + cell_size=cell_size, + sources=sources, + geometry=geometry, + boundary_layers=boundary_layers, + k_point=k_point) + + flux = sim.add_mode_monitor(fcen, + 0, + 1, + mp.ModeRegion(center=mp.Vector3(0,0,0.5*sz-dpml), + size=mp.Vector3(px,py,0))) + + sim.run(until_after_sources=mp.stop_when_dft_decayed()) + + res = sim.get_eigenmode_coefficients(flux, + mp.DiffractedPlanewave((1,0,0), + mp.Vector3(0,0,1), + 0 if P_pol else 1, + 1 if P_pol else 0)) + + coeffs = res.alpha + Tmeep = abs(coeffs[0,0,0])**2 / input_flux[0] + + n1 = 1.0 + n2 = nSiO2 + Tfresnel = 1 - (n1-n2)**2 / (n1+n2)**2 + diff_eff_P = 0.9114 # P-pol. diffraction efficiency computed using Reticolo (RCWA) + diff_eff_S = 0.9514 # S-pol. diffraction efficiency computed using Reticolo (RCWA) + # convert diffraction efficiency into transmittance in the Z direction + Treticolo = (diff_eff_P if P_pol else diff_eff_S) * Tfresnel * math.cos(theta_d) + err = abs(Tmeep - Treticolo) / Treticolo + print("err:, {}, {:.6f} (Meep), {:.6f} (reticolo), {:.6f} (error),".format('P' if P_pol else 'S',Tmeep,Treticolo,err)) + + # for debugging: + # visualize cross sections of the computational cell + # to ensure that metagrating matches expected design + if 0: + output_plane = mp.Volume(center=mp.Vector3(0,0,0.5*sz-dpml-dair-0.5*gh), + size=mp.Vector3(px,py,0)) + plt.figure() + sim.plot2D(output_plane=output_plane, + eps_parameters={'resolution':100}) + plt.savefig('cell_xy.png',dpi=150,bbox_inches='tight') + + output_plane = mp.Volume(center=mp.Vector3(0,0,0), + size=mp.Vector3(0,py,sz)) + plt.figure() + sim.plot2D(output_plane=output_plane, + eps_parameters={'resolution':100}) + plt.savefig('cell_yz.png',dpi=150,bbox_inches='tight') + + output_plane = mp.Volume(center=mp.Vector3(0,0,0), + size=mp.Vector3(px,0,sz)) + plt.figure() + sim.plot2D(output_plane=output_plane, + eps_parameters={'resolution':100}) + plt.savefig('cell_xz.png',dpi=150,bbox_inches='tight') + + return err + +if __name__ == '__main__': + metagrating(False) + metagrating(True) From 55bea38acb0cc37de10557566ebcbccfcc920725 Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Mon, 18 Apr 2022 10:32:33 -0700 Subject: [PATCH 2/4] minor fixes --- Metagrating3D/metagrating-meep.py | 57 +++++++++++++------------------ 1 file changed, 23 insertions(+), 34 deletions(-) diff --git a/Metagrating3D/metagrating-meep.py b/Metagrating3D/metagrating-meep.py index 2bb17ca..7bef3d2 100644 --- a/Metagrating3D/metagrating-meep.py +++ b/Metagrating3D/metagrating-meep.py @@ -1,19 +1,14 @@ -# compute the transmittance of the m=+1 order +# Computes the transmittance of the m=+1 order # for a 3d metagrating with the 2d design # imported from the file device1.csv -# and compare the result with the expected value -# from RCWA (Reticolo) import meep as mp import math import numpy as np -import matplotlib -matplotlib.use('agg') -import matplotlib.pyplot as plt def metagrating(P_pol: bool): - resolution = 50 # pixels/μm + resolution = 100 # pixels/μm nSi = 3.45 Si = mp.Medium(index=nSi) @@ -28,10 +23,10 @@ def metagrating(P_pol: bool): px = wvl/math.sin(theta_d) # period in x py = 0.5*wvl # period in y - dpml = wvl # PML thickness + dpml = 1.0 # PML thickness gh = 0.325 # grating height - dsub = 3.0 # substrate thickness - dair = 3.0 # air padding + dsub = 5.0 # substrate thickness + dair = 5.0 # air padding sz = dpml+dsub+gh+dair+dpml @@ -42,15 +37,12 @@ def metagrating(P_pol: bool): # periodic boundary conditions k_point = mp.Vector3() - ## disabled due to https://github.com/NanoComp/meep/issues/132 - # symmetries = [mp.Mirror(direction=mp.Y)] - # plane of incidence is XZ - # P/TM polarization: Ex, S/TE polarization: Ey src_cmpt = mp.Ex if P_pol else mp.Ey - sources = [mp.Source(src=mp.GaussianSource(fcen,fwidth=0.2*fcen), + src_pt = mp.Vector3(0,0,-0.5*sz+dpml+0.5*dsub) + sources = [mp.Source(src=mp.GaussianSource(fcen,fwidth=0.1*fcen), size=mp.Vector3(px,py,0), - center=mp.Vector3(0,0,-0.5*sz+dpml), + center=src_pt, component=src_cmpt)] sim = mp.Simulation(resolution=resolution, @@ -64,14 +56,17 @@ def metagrating(P_pol: bool): 0, 1, mp.ModeRegion(center=mp.Vector3(0,0,0.5*sz-dpml), - size=mp.Vector3(px,py,0))) + size=mp.Vector3(px,py,0))) - sim.run(until_after_sources=mp.stop_when_dft_decayed()) + stop_cond = mp.stop_when_fields_decayed(10,src_cmpt,src_pt,1e-7) + sim.run(until_after_sources=stop_cond) input_flux = mp.get_fluxes(flux) sim.reset_meep() + # image resolution is ~340 pixels/μm and thus + # Meep resolution should not be larger than ~half this value weights = np.genfromtxt('device1.csv',delimiter=',') Nx, Ny = weights.shape @@ -98,31 +93,26 @@ def metagrating(P_pol: bool): mp.ModeRegion(center=mp.Vector3(0,0,0.5*sz-dpml), size=mp.Vector3(px,py,0))) - sim.run(until_after_sources=mp.stop_when_dft_decayed()) + sim.run(until_after_sources=stop_cond) res = sim.get_eigenmode_coefficients(flux, mp.DiffractedPlanewave((1,0,0), - mp.Vector3(0,0,1), + mp.Vector3(1,0,0), 0 if P_pol else 1, 1 if P_pol else 0)) coeffs = res.alpha - Tmeep = abs(coeffs[0,0,0])**2 / input_flux[0] - - n1 = 1.0 - n2 = nSiO2 - Tfresnel = 1 - (n1-n2)**2 / (n1+n2)**2 - diff_eff_P = 0.9114 # P-pol. diffraction efficiency computed using Reticolo (RCWA) - diff_eff_S = 0.9514 # S-pol. diffraction efficiency computed using Reticolo (RCWA) - # convert diffraction efficiency into transmittance in the Z direction - Treticolo = (diff_eff_P if P_pol else diff_eff_S) * Tfresnel * math.cos(theta_d) - err = abs(Tmeep - Treticolo) / Treticolo - print("err:, {}, {:.6f} (Meep), {:.6f} (reticolo), {:.6f} (error),".format('P' if P_pol else 'S',Tmeep,Treticolo,err)) + tran = abs(coeffs[0,0,0])**2 / input_flux[0] + print("tran:, {}, {:.6f}".format('P' if P_pol else 'S',tran)) # for debugging: - # visualize cross sections of the computational cell - # to ensure that metagrating matches expected design + # visualize three orthogonal cross sections of the 3D cell + # to ensure that structure matches expected design if 0: + import matplotlib + matplotlib.use('agg') + import matplotlib.pyplot as plt + output_plane = mp.Volume(center=mp.Vector3(0,0,0.5*sz-dpml-dair-0.5*gh), size=mp.Vector3(px,py,0)) plt.figure() @@ -144,7 +134,6 @@ def metagrating(P_pol: bool): eps_parameters={'resolution':100}) plt.savefig('cell_xz.png',dpi=150,bbox_inches='tight') - return err if __name__ == '__main__': metagrating(False) From 65b1d7a0b7af6e50528bcefd41237d54e84c4f92 Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Sat, 7 May 2022 15:22:35 +0000 Subject: [PATCH 3/4] disable subpixel averaging to ensure field stability --- Metagrating3D/metagrating-meep.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Metagrating3D/metagrating-meep.py b/Metagrating3D/metagrating-meep.py index 7bef3d2..a0eec19 100644 --- a/Metagrating3D/metagrating-meep.py +++ b/Metagrating3D/metagrating-meep.py @@ -1,5 +1,5 @@ # Computes the transmittance of the m=+1 order -# for a 3d metagrating with the 2d design +# for a 3D metagrating with the 2D design # imported from the file device1.csv import meep as mp @@ -85,7 +85,8 @@ def metagrating(P_pol: bool): sources=sources, geometry=geometry, boundary_layers=boundary_layers, - k_point=k_point) + k_point=k_point, + eps_averaging=False) flux = sim.add_mode_monitor(fcen, 0, From 8c6ef441f74bf6d48ae06a492d7aa20cf0385b1e Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Fri, 20 May 2022 17:04:09 -0700 Subject: [PATCH 4/4] add Meep results to README.md --- Metagrating3D/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Metagrating3D/README.md b/Metagrating3D/README.md index 2270239..23b5d10 100644 --- a/Metagrating3D/README.md +++ b/Metagrating3D/README.md @@ -33,9 +33,11 @@ As an example, optimized metagrating designs with following parameters can be fo - **Unit Cell**: Nx = 472, Ny = 180 The deflection efficiencies for the example device in this repo are: -- **Device1**: TM 95.7% -- **Device2**: TM 93.3% -- **Device3**: TM 96.6% +- **Device1**: TM 95.7% (RETICOLO/RCWA), 95.5% (MEEP/FDTD) +- **Device2**: TM 93.3% (RETICOLO/RCWA), 93.6% (MEEP/FDTD) +- **Device3**: TM 96.6% (RETICOLO/RCWA), 95.0% (MEEP/FDTD) + +The MEEP results were obtained using `metagrating.meep.py`. `device.mat` file contains all optimization parameters and final device pattern in matlab format while `device.csv` is the optimized device pattern (2D matrix) in csv format.