1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
|
from __future__ import division
import unittest
import numpy as np
import meep as mp
class TestModeCoeffs(unittest.TestCase):
def run_mode_coeffs(self, mode_num, kpoint_func):
resolution = 15
w = 1 # width of waveguide
L = 10 # length of waveguide
Si = mp.Medium(epsilon=12.0)
dair = 3.0
dpml = 3.0
sx = dpml + L + dpml
sy = dpml + dair + w + dair + dpml
cell_size = mp.Vector3(sx, sy, 0)
prism_x = sx + 1
prism_y = w / 2
vertices = [mp.Vector3(-prism_x, prism_y),
mp.Vector3(prism_x, prism_y),
mp.Vector3(prism_x, -prism_y),
mp.Vector3(-prism_x, -prism_y)]
geometry = [mp.Prism(vertices, height=mp.inf, material=Si)]
boundary_layers = [mp.PML(dpml)]
# mode frequency
fcen = 0.20 # > 0.5/sqrt(11) to have at least 2 modes
sources = [mp.EigenModeSource(src=mp.GaussianSource(fcen, fwidth=0.5*fcen),
eig_band=mode_num,
size=mp.Vector3(0,sy-2*dpml,0),
center=mp.Vector3(-0.5*sx+dpml,0,0),
eig_match_freq=True,
eig_resolution=32) ]
sim = mp.Simulation(resolution=resolution,
cell_size=cell_size,
boundary_layers=boundary_layers,
geometry=geometry,
sources=sources,
symmetries=[mp.Mirror(mp.Y, phase=1 if mode_num % 2 == 1 else -1)])
xm = 0.5*sx - dpml # x-coordinate of monitor
mflux = sim.add_mode_monitor(fcen, 0, 1, mp.ModeRegion(center=mp.Vector3(xm,0), size=mp.Vector3(0,sy-2*dpml)))
mode_flux = sim.add_flux(fcen, 0, 1, mp.FluxRegion(center=mp.Vector3(xm,0), size=mp.Vector3(0,sy-2*dpml)))
# sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, mp.Vector3(-0.5*sx+dpml,0), 1e-10))
sim.run(until_after_sources=100)
modes_to_check = [1, 2] # indices of modes for which to compute expansion coefficients
res = sim.get_eigenmode_coefficients(mflux, modes_to_check, kpoint_func=kpoint_func)
self.assertTrue(res.kpoints[0].close(mp.Vector3(0.604301, 0, 0)))
self.assertTrue(res.kpoints[1].close(mp.Vector3(0.494353, 0, 0), tol=1e-2))
self.assertTrue(res.kdom[0].close(mp.Vector3(0.604301, 0, 0)))
self.assertTrue(res.kdom[1].close(mp.Vector3(0.494353, 0, 0), tol=1e-2))
mode_power = mp.get_fluxes(mode_flux)[0]
TestPassed = True
TOLERANCE = 5.0e-3
c0 = res.alpha[mode_num - 1, 0, 0] # coefficient of forward-traveling wave for mode #mode_num
for nm in range(1, len(modes_to_check)+1):
if nm != mode_num:
cfrel = np.abs(res.alpha[nm - 1, 0, 0]) / np.abs(c0)
cbrel = np.abs(res.alpha[nm - 1, 0, 1]) / np.abs(c0)
if cfrel > TOLERANCE or cbrel > TOLERANCE:
TestPassed = False
self.sim = sim
# test 1: coefficient of excited mode >> coeffs of all other modes
self.assertTrue(TestPassed, msg="cfrel: {}, cbrel: {}".format(cfrel, cbrel))
# test 2: |mode coeff|^2 = power
self.assertAlmostEqual(mode_power / abs(c0**2), 1.0, places=1)
return res
def test_modes(self):
self.run_mode_coeffs(1, None)
res = self.run_mode_coeffs(2, None)
# Test mp.get_eigenmode and EigenmodeData
vol = mp.Volume(center=mp.Vector3(5), size=mp.Vector3(y=7))
emdata = self.sim.get_eigenmode(0.2, mp.X, vol, 2, mp.Vector3())
self.assertEqual(emdata.freq, 0.2)
self.assertEqual(emdata.band_num, 2)
self.assertTrue(emdata.kdom.close(res.kdom[1]))
eval_point = mp.Vector3(0.7, -0.2, 0.3)
ex_at_eval_point = emdata.amplitude(eval_point, mp.Ex)
hz_at_eval_point = emdata.amplitude(eval_point, mp.Hz)
self.assertAlmostEqual(ex_at_eval_point, 0.10591314723115094+0.12458333138964374j, places=2)
self.assertAlmostEqual(hz_at_eval_point, 0.8681206797182762-0.737695596449452j, places=2)
def test_kpoint_func(self):
def kpoint_func(freq, mode):
return mp.Vector3()
self.run_mode_coeffs(1, kpoint_func)
if __name__ == '__main__':
unittest.main()
|