Repository: NanoComp/meep

Issue #1470: non-reciprocal S-parameters using add_mode_monitor 
Created: 2021-01-14T05:40:19Z
The function add_mode_monitor used for eigenmode decomposition seems to produce non-reciprocal S-parameters as demonstrated below when computing the 2x2 scattering matrix of a straight waveguide in which S12 ≠ S21 at finite resolutions. This non-reciprocal effect is independent of whether the argument yee_grid is True or False. (This example does not involve the use of symmetries but does involve specifying the eig_parity of the mode.) A convergence plot of the relative error in S12 and S21 using yee_grid=True (snapping the fields to the Yee grid) and yee_grid=False (centering the fields at the voxel center) versus resolution shows that the non-reciprocity vanishes with increasing resolution and that the convergence rate is the same in all cases. Nevertheless, it would be useful for add_mode_monitor to preserve reciprocity at finite resolutions.


The S12 computation involves placing an eigenmode source at the left edge of the waveguide (shown in the figure below as the red line) and the mode monitor at the right edge (blue line).

The S21 computation involves the swapping the location of the source and mode monitor (i.e., source is on the right and monitor is on the left).

Results were generating using the following script.
import meep as mp
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-res', type=int,
                    default=50,
                    help='resolution (default: 50 pixels/um)')
args = parser.parse_args()

mp.verbosity(1)

dpml = 1.0

silicon = mp.Medium(epsilon=12)

fcen = 1/1.55
df = 0.2*fcen

sxy = 5.0

cell_size = mp.Vector3(sxy,sxy,0)

boundary_layers = [mp.PML(thickness=dpml)]

eig_parity = mp.EVEN_Y+mp.ODD_Z

w = 0.6 # waveguide width                                                                                                                                                              

geometry = [mp.Block(material=silicon,
                     center=mp.Vector3(),
                     size=mp.Vector3(mp.inf,w,mp.inf))

# source is at the left edge of the waveguide
sources = [mp.EigenModeSource(src=mp.GaussianSource(fcen,fwidth=df),
                              center=mp.Vector3(-0.5*sxy+dpml,0),
                              size=mp.Vector3(0,sxy,0),
                              eig_band=1,
                              eig_parity=eig_parity,
                              eig_match_freq=True)]

sim = mp.Simulation(resolution=args.res,
                    cell_size=cell_size,
                    boundary_layers=boundary_layers,
                    sources=sources,
                    geometry=geometry)

# monitor is at the right edge of the waveguide
mode = sim.add_mode_monitor(fcen, 0, 1,
                            mp.ModeRegion(center=mp.Vector3(0.5*sxy-dpml),size=mp.Vector3(0,sxy,0)),
                            yee_grid=True)

sim.run(until_after_sources=20)

# mode coefficient of forward-propagating mode                                                                                                                                                                   
coeff = sim.get_eigenmode_coefficients(mode,[1],eig_parity).alpha[0,0,0]

# S parameters                                                                                                                                                                         
S12 = abs(coeff)**2

print("S12:, {}, {:.14f}".format(args.res,S12))

sim.reset_meep()

# source is at the right edge of the waveguide
sources = [mp.EigenModeSource(src=mp.GaussianSource(fcen,fwidth=df),
                              center=mp.Vector3(0.5*sxy-dpml,0),
                              size=mp.Vector3(0,sxy,0),
                              eig_band=1,
                              eig_parity=eig_parity,
                              eig_match_freq=True,
                              direction=mp.NO_DIRECTION,
                              eig_kpoint=mp.Vector3(-1))]

sim = mp.Simulation(resolution=args.res,
                    cell_size=cell_size,
                    boundary_layers=boundary_layers,
                    sources=sources,
                    geometry=geometry)

# monitor is at the left edge of the waveguide
mode = sim.add_mode_monitor(fcen, 0, 1,
                            mp.ModeRegion(center=mp.Vector3(-0.5*sxy+dpml),size=mp.Vector3(0,sxy,0)),
                            yee_grid=True)

sim.run(until_after_sources=20)

# mode coefficient of backward-propagating mode                                                                                                                                                                    
coeff = sim.get_eigenmode_coefficients(mode,[1],eig_parity).alpha[0,0,1]

# S parameters                                                                                                                                                                         
S21 = abs(coeff)**2

print("S21:, {}, {:.14f}".format(args.res,S21))

Duplicate issue #1795: Incorrect Backward Eigenmode Calculation
Created: 2021-10-19T23:54:58Z
Hi all,
I read up on some of the previous issues regarding incorrect backward mode calculations (issues #1773 and #1585 mainly). It seemed like #1585  was supposed to be resolved in v1.21(see #1593) but I still encounter the same problem when running some small tests with the newest version. I was hoping someone can either look into this or correct a mistake on my end if I am using something incorrectly. I've included the geometry, code, and resulting plots below
inf_wg_dipole.zip

To summarize, I ran a simple 2D simulation with a y-oriented dipole source in the middle of an infinite GaAs waveguide and was comparing the coupling efficiency of the forward(+) mode to the backward(-) mode (expecting those to be the same). However, that was not the case as I got the following plot:

I am not too concerned with the shape of the plots, only understanding why there is such a large disagreement between the forward and backward modes.
Worth mentioning: increasing the resolution pushes the (-) eigenmode coupling closer to the (+) result, but you have to use a pretty large resolution to get a perfect match (unnecessarily large for such a simple sim).
I would appreciate it if anyone is able to explain why this is occurring; Is it definitely a bug buried deep somewhere within meep or am I implementing something incorrectly(e.g, the method of setting up flux regions to record fluxes and get eigenmode coefficients)? Please let me know if I can provide anything else to help clarify the issue.
Thank you!

Closing comment (2021-10-20T00:13:09Z): What you are seeing has been previously reported in #1470.