def create_adjoint_sources( monitors: Iterable[ObjectiveQuantity], monitor_values_grad: onp.ndarray) -> List[mp.Source]: monitor_values_grad = onp.asarray( monitor_values_grad, dtype=onp.complex64 if mp.is_single_precision() else onp.complex128) if not onp.any(monitor_values_grad): raise RuntimeError( 'The gradient of all monitor values is zero, which ' 'means that no adjoint sources can be placed to set ' 'up an adjoint simulation in Meep. Possible causes ' 'could be:\n\n' ' * the forward simulation was not run for long enough ' 'to allow the input pulse(s) to reach the monitors' ' * the monitor values are disconnected from the ' 'objective function output.') adjoint_sources = [] for monitor_idx, monitor in enumerate(monitors): # `dj` for each monitor will have a shape of (num frequencies,) dj = onp.asarray(monitor_values_grad[monitor_idx], dtype=onp.complex64 if mp.is_single_precision() else onp.complex128) if onp.any(dj): adjoint_sources += monitor.place_adjoint_source(dj) assert adjoint_sources return adjoint_sources
def test_1d_slice_user_array(self): self.sim.run(until_after_sources=0) arr = np.zeros( 126, dtype=np.float32 if mp.is_single_precision() else np.float64) vol = mp.Volume(center=self.center_1d, size=self.size_1d) self.sim.get_array(mp.Hz, vol, arr=arr) tol = 1e-5 if mp.is_single_precision() else 1e-8 self.assertClose(self.expected_1d, arr, epsilon=tol)
def test_adjoint_solver_eigenmode(self): print("*** TESTING EIGENMODE ADJOINT ***") ## test the single frequency and multi frequency case for frequencies in [[fcen], [1 / 1.58, fcen, 1 / 1.53]]: ## compute gradient using adjoint solver adjsol_obj, adjsol_grad = adjoint_solver(p, MonitorObject.EIGENMODE, frequencies) ## compute unperturbed S12 S12_unperturbed = forward_simulation(p, MonitorObject.EIGENMODE, frequencies) ## compare objective results print( "S12 -- adjoint solver: {}, traditional simulation: {}".format( adjsol_obj, S12_unperturbed)) self.assertClose(adjsol_obj, S12_unperturbed, epsilon=1e-6) ## compute perturbed S12 S12_perturbed = forward_simulation(p + dp, MonitorObject.EIGENMODE, frequencies) ## compare gradients if adjsol_grad.ndim < 2: adjsol_grad = np.expand_dims(adjsol_grad, axis=1) adj_scale = (dp[None, :] @ adjsol_grad).flatten() fd_grad = S12_perturbed - S12_unperturbed print( "Directional derivative -- adjoint solver: {}, FD: {}".format( adj_scale, fd_grad)) tol = 0.04 if mp.is_single_precision() else 0.01 self.assertClose(adj_scale, fd_grad, epsilon=tol)
def test_complex_fields(self): print("*** TESTING COMPLEX FIELDS ***") for frequencies in [[fcen], [1 / 1.58, fcen, 1 / 1.53]]: ## compute gradient using adjoint solver adjsol_obj, adjsol_grad = adjoint_solver_complex_fields( p, frequencies) ## compute unperturbed |Ez|^2 Ez2_unperturbed = forward_simulation_complex_fields(p, frequencies) ## compare objective results print( "Ez2 -- adjoint solver: {}, traditional simulation: {}".format( adjsol_obj, Ez2_unperturbed)) self.assertClose(adjsol_obj, Ez2_unperturbed, epsilon=1e-6) ## compute perturbed |Ez|^2 Ez2_perturbed = forward_simulation_complex_fields( p + dp, frequencies) ## compare gradients if adjsol_grad.ndim < 2: adjsol_grad = np.expand_dims(adjsol_grad, axis=1) adj_scale = (dp[None, :] @ adjsol_grad).flatten() fd_grad = Ez2_perturbed - Ez2_unperturbed print( "Directional derivative -- adjoint solver: {}, FD: {}".format( adj_scale, fd_grad)) tol = 0.018 if mp.is_single_precision() else 0.002 self.assertClose(adj_scale, fd_grad, epsilon=tol)
def test_resonant_modes(self): self.sim.sources = [ mp.Source(mp.GaussianSource(self.fcen, fwidth=self.df), mp.Hz, mp.Vector3()) ] self.sim.symmetries = [ mp.Mirror(mp.Y, phase=-1), mp.Mirror(mp.X, phase=-1) ] self.sim.use_output_directory(self.temp_dir) h = mp.Harminv(mp.Hz, mp.Vector3(), self.fcen, self.df) self.sim.run(mp.at_beginning(mp.output_epsilon), mp.after_sources(h), until_after_sources=400) expected = [ 0.23445415346009466, -3.147812367338531e-4, 372.40808234438254, 5.8121430334347135, -3.763107485715599, -4.429450156854109, ] m = h.modes[0] res = [m.freq, m.decay, m.Q, abs(m.amp), m.amp.real, m.amp.imag] tol = 1e-6 if mp.is_single_precision() else 1e-8 self.assertClose(expected, res, epsilon=tol)
def test_damping(self): print("*** TESTING CONDUCTIVITIES ***") for frequencies in [[1 / 1.58, fcen, 1 / 1.53]]: ## compute gradient using adjoint solver adjsol_obj, adjsol_grad = adjoint_solver_damping(p, frequencies) ## compute unperturbed S12 S12_unperturbed = forward_simulation_damping(p, frequencies) ## compare objective results print( "S12 -- adjoint solver: {}, traditional simulation: {}".format( adjsol_obj, S12_unperturbed)) self.assertClose(adjsol_obj, S12_unperturbed, epsilon=1e-6) ## compute perturbed S12 S12_perturbed = forward_simulation_damping(p + dp, frequencies) ## compare gradients if adjsol_grad.ndim < 2: adjsol_grad = np.expand_dims(adjsol_grad, axis=1) adj_scale = (dp[None, :] @ adjsol_grad).flatten() fd_grad = S12_perturbed - S12_unperturbed print( "Directional derivative -- adjoint solver: {}, FD: {}".format( adj_scale, fd_grad)) tol = 0.06 if mp.is_single_precision() else 0.03 self.assertClose(adj_scale, fd_grad, epsilon=tol)
def test_fields_at_kx(self): self.sim.k_point = mp.Vector3(3.5) h = mp.Harminv(mp.Hz, mp.Vector3(0.1234), self.fcen, self.df) self.sim.run(mp.after_sources(h), until_after_sources=300) expected = [ (0.19990240131986522, 3.8522735413802275e-8), (0.3050067740183294, 4.720168254531566e-7), (0.4396104226078593, 1.6233300291010948e-6), (0.4582004346509184, 4.7150006592976396e-7), (0.5006556112859917, -0.0014396635723422887), (0.7405953267896378, -4.553109069353934e-5), (0.7627621012715363, -0.006700351645723407), (0.8243404528365005, -5.174379068176951e-4), (0.8255990399390389, -0.0016256261502000271), (0.9494859645499801, -0.005325208458639275), (0.9726561278186849, -0.0031192234222098274), (0.9855957702101914, -0.003945157134867143), ] self.assertTrue(h.modes) places = 4 if mp.is_single_precision() else 7 for (r, i), m in zip(expected, h.modes): self.assertAlmostEqual(m.freq, r, places=places) self.assertAlmostEqual(m.decay, i, places=places)
def test_adjoint_solver_cyl_n2f_fields(self): print("*** TESTING CYLINDRICAL Near2Far ADJOINT FEATURES ***") adjsol_obj, adjsol_grad = adjoint_solver(p) ## compute unperturbed S12 S12_unperturbed = forward_simulation(p) ## compare objective results print( "|Er|^2 -- adjoint solver: {}, traditional simulation: {}".format( adjsol_obj, S12_unperturbed)) self.assertClose(adjsol_obj, S12_unperturbed, epsilon=1e-3) ## compute perturbed S12 S12_perturbed = forward_simulation(p + dp) ## compare gradients if adjsol_grad.ndim < 2: adjsol_grad = np.expand_dims(adjsol_grad, axis=1) adj_scale = (dp[None, :] @ adjsol_grad).flatten() fd_grad = S12_perturbed - S12_unperturbed print("Directional derivative -- adjoint solver: {}, FD: {}".format( adj_scale, fd_grad)) tol = 0.2 if mp.is_single_precision() else 0.1 self.assertClose(adj_scale, fd_grad, epsilon=tol)
def test_refl_angular(self, theta): fmeep, tmeep, Rmeep = self.refl_angular(theta) # angle of refracted planewave in medium n2 for an # incident planewave in medium n1 at angle theta_in theta_out = lambda theta_in: math.asin(self.n1 * math.sin(theta_in) / self.n2) # Fresnel reflectance for P polarization in medium n2 for # an incident planewave in medium n1 at angle theta_in Rfresnel = lambda theta_in: (math.fabs( (self.n1 * math.cos(theta_out(theta_in)) - self .n2 * math.cos(theta_in)) / (self.n1 * math.cos( theta_out(theta_in)) + self.n2 * math.cos(theta_in)))**2) Ranalytic = np.empty((self.nfreq, )) print( "refl:, wavelength (μm), incident angle (°), reflectance (Meep), reflectance (analytic), error" ) for i in range(self.nfreq): Ranalytic[i] = Rfresnel(tmeep[i]) err = abs(Rmeep[i] - Ranalytic[i]) / Ranalytic[i] print("refl:, {:4.2f}, {:4.2f}, {:8.6f}, {:8.6f}, {:6.4f}".format( 1 / fmeep[i], math.degrees(tmeep[i]), Rmeep[i], Ranalytic[i], err)) tol = 0.005 if mp.is_single_precision() else 0.004 self.assertClose(Rmeep, Ranalytic, epsilon=tol)
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) places = 6 if mp.is_single_precision() else 7 self.assertAlmostEqual(res1, 0.17158099566244897, places=places)
def test_gradient_backpropagation(self): print("*** TESTING BACKPROP ***") for frequencies in [[fcen], [1 / 1.58, fcen, 1 / 1.53]]: ## filter/thresholding parameters filter_radius = 0.21985 eta = 0.49093 beta = 4.0698 mapped_p = mapping(p, filter_radius, eta, beta) ## compute gradient using adjoint solver adjsol_obj, adjsol_grad = adjoint_solver(mapped_p, MonitorObject.EIGENMODE, frequencies) ## backpropagate the gradient if len(frequencies) > 1: bp_adjsol_grad = np.zeros(adjsol_grad.shape) for i in range(len(frequencies)): bp_adjsol_grad[:, i] = tensor_jacobian_product(mapping, 0)( p, filter_radius, eta, beta, adjsol_grad[:, i]) else: bp_adjsol_grad = tensor_jacobian_product(mapping, 0)(p, filter_radius, eta, beta, adjsol_grad) ## compute unperturbed S12 S12_unperturbed = forward_simulation(mapped_p, MonitorObject.EIGENMODE, frequencies) ## compare objective results print( "S12 -- adjoint solver: {}, traditional simulation: {}".format( adjsol_obj, S12_unperturbed)) self.assertClose(adjsol_obj, S12_unperturbed, epsilon=1e-6) ## compute perturbed S12 S12_perturbed = forward_simulation( mapping(p + dp, filter_radius, eta, beta), MonitorObject.EIGENMODE, frequencies) if bp_adjsol_grad.ndim < 2: bp_adjsol_grad = np.expand_dims(bp_adjsol_grad, axis=1) adj_scale = (dp[None, :] @ bp_adjsol_grad).flatten() fd_grad = S12_perturbed - S12_unperturbed print( "Directional derivative -- adjoint solver: {}, FD: {}".format( adj_scale, fd_grad)) tol = 0.02 if mp.is_single_precision() else 0.01 self.assertClose(adj_scale, fd_grad, epsilon=tol)
def test_divide_parallel_processes(self): resolution = 20 sxy = 4 dpml = 1 cell = mp.Vector3(sxy + 2 * dpml, sxy + 2 * dpml) pml_layers = [mp.PML(dpml)] n = mp.divide_parallel_processes(2) fcen = 1.0 / (n + 1) sources = [ mp.Source(src=mp.GaussianSource(fcen, fwidth=0.2 * fcen), center=mp.Vector3(), component=mp.Ez) ] symmetries = [mp.Mirror(mp.X), mp.Mirror(mp.Y)] self.sim = mp.Simulation(cell_size=cell, resolution=resolution, sources=sources, symmetries=symmetries, boundary_layers=pml_layers) flux_box = self.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), decimation_factor=1) self.sim.run(until_after_sources=30) tot_flux = mp.get_fluxes(flux_box)[0] tot_fluxes = mp.merge_subgroup_data(tot_flux) fcens = mp.merge_subgroup_data(fcen) self.assertEqual(fcens[0], 1) self.assertEqual(fcens[1], 0.5) places = 4 if mp.is_single_precision() else 7 self.assertAlmostEqual(tot_fluxes[0], 9.8628728533, places=places) self.assertAlmostEqual(tot_fluxes[1], 19.6537275387, places=places)
def test_user_material_func(self): sim = mp.Simulation(cell_size=self.cell, resolution=self.resolution, symmetries=self.symmetries, boundary_layers=self.boundary_layers, sources=self.sources, material_function=my_material_func) sim.run(until=200) fp = sim.get_field_point(mp.Ez, mp.Vector3(x=1)) places = 3 if mp.is_single_precision() else 7 self.assertAlmostEqual(fp, 4.816403627871773e-4, places=places)
def test_3rd_harm_1d(self): expected_harmonics = [0.01, 1.0, 221.89548712071553, 1.752960413399477] self.sim.run( until_after_sources=mp.stop_when_fields_decayed( 50, mp.Ex, mp.Vector3(0, 0, (0.5 * self.sz) - self.dpml - 0.5), 1e-6 ) ) harmonics = [self.k, self.amp, mp.get_fluxes(self.trans1)[0], mp.get_fluxes(self.trans3)[0]] tol = 3e-5 if mp.is_single_precision() else 1e-7 self.assertClose(expected_harmonics, harmonics, epsilon=tol)
def test_pw_source(self): self.sim.run(mp.at_end(mp.output_efield_z), until=400) v1 = mp.Vector3(0.5 * self.s, 0) v2 = mp.Vector3(0.5 * self.s, 0.5 * self.s) pt1 = self.sim.get_field_point(mp.Ez, v1) pt2 = self.sim.get_field_point(mp.Ez, v2) tol = 1e-4 if mp.is_single_precision() else 1e-9 self.assertClose(pt1 / pt2, 27.557668029008262, epsilon=tol) self.assertAlmostEqual(cmath.exp(1j * self.k.dot(v1 - v2)), 0.7654030066070924 - 0.6435512702783076j)
def test_offdiagonal(self): print("*** TESTING OFFDIAGONAL COMPONENTS ***") filt = lambda x: mpa.conic_filter(x.reshape( (Nx, Ny)), 0.25, design_region_size.x, design_region_size.y, design_region_resolution).flatten() ## test the single frequency and multi frequency case for frequencies in [[fcen], [1 / 1.58, fcen, 1 / 1.53]]: ## compute gradient using adjoint solver adjsol_obj, adjsol_grad = adjoint_solver(filt(p), MonitorObject.EIGENMODE, frequencies, sapphire) ## backpropagate the gradient if len(frequencies) > 1: bp_adjsol_grad = np.zeros(adjsol_grad.shape) for i in range(len(frequencies)): bp_adjsol_grad[:, i] = tensor_jacobian_product(filt, 0)( p, adjsol_grad[:, i]) else: bp_adjsol_grad = tensor_jacobian_product(filt, 0)(p, adjsol_grad) ## compute unperturbed S12 S12_unperturbed = forward_simulation(filt(p), MonitorObject.EIGENMODE, frequencies, sapphire) ## compare objective results print( "S12 -- adjoint solver: {}, traditional simulation: {}".format( adjsol_obj, S12_unperturbed)) self.assertClose(adjsol_obj, S12_unperturbed, epsilon=1e-6) ## compute perturbed S12 S12_perturbed = forward_simulation(filt(p + dp), MonitorObject.EIGENMODE, frequencies, sapphire) ## compare gradients if bp_adjsol_grad.ndim < 2: bp_adjsol_grad = np.expand_dims(bp_adjsol_grad, axis=1) adj_scale = (dp[None, :] @ bp_adjsol_grad).flatten() fd_grad = S12_perturbed - S12_unperturbed print( "Directional derivative -- adjoint solver: {}, FD: {}".format( adj_scale, fd_grad)) tol = 0.1 if mp.is_single_precision() else 0.04 self.assertClose(adj_scale, fd_grad, epsilon=tol)
def test_numpy_epsilon(self): sim = self.init_simple_simulation() eps_input_fname = 'cyl-ellipsoid-eps-ref.h5' eps_input_dir = os.path.abspath( os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', 'tests')) eps_input_path = os.path.join(eps_input_dir, eps_input_fname) with h5py.File(eps_input_path, 'r') as f: sim.default_material = f['eps'][()] sim.run(until=200) fp = sim.get_field_point(mp.Ez, mp.Vector3(x=1)) places = 6 if mp.is_single_precision() else 7 self.assertAlmostEqual(fp, -0.002989654055823199, places=places)
def call_chi1(self,material,frequency): sim = mp.Simulation(cell_size=mp.Vector3(1,1,1), default_material=material, resolution=20) sim.init_sim() v3 = mp.py_v3_to_vec(sim.dimensions, mp.Vector3(0,0,0), sim.is_cylindrical) chi1inv = np.zeros((3,3),dtype=np.complex128) for i, com in enumerate([mp.Ex,mp.Ey,mp.Ez]): for k, dir in enumerate([mp.X,mp.Y,mp.Z]): chi1inv[i,k] = sim.structure.get_chi1inv(com,dir,v3,frequency) n = np.real(np.sqrt(np.linalg.inv(chi1inv.astype(np.complex128)))) n_actual = np.real(np.sqrt(material.epsilon(frequency).astype(np.complex128))) tol = 1e-6 if mp.is_single_precision() else 1e-8 self.assertClose(n, n_actual, epsilon=tol)
def test_ring_cyl(self): expected = [ 0.11835455441250553, -6.907792691629741e-4, 85.66741917133473, 0.025701906263451237, -0.024027038833537524, -0.009126302124459489, ] h = mp.Harminv(mp.Ez, mp.Vector3(self.r + 0.1), self.fcen, self.df) self.sim.run(mp.after_sources(h), until_after_sources=200) m = h.modes[0] res = [m.freq, m.decay, m.Q, abs(m.amp), m.amp.real, m.amp.imag] tol = 1e-6 if mp.is_single_precision() else 1e-7 self.assertClose(expected, res, epsilon=tol)
def test_force(self): self.sim.run(until_after_sources=mp.stop_when_fields_decayed( 50, mp.Ez, mp.Vector3(), 1e-6)) # Test store and load of force as numpy array fdata = self.sim.get_force_data(self.myforce) self.sim.load_force_data(self.myforce, fdata) self.sim.display_forces(self.myforce) f = mp.get_forces(self.myforce) self.assertAlmostEqual(f[0], -0.11039089113393187) places = 6 if mp.is_single_precision() else 7 self.assertAlmostEqual(f[0], mp.get_forces(self.myforce_decimated)[0], places=places)
def test_custom_source(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(r + w, material=mp.Medium(index=n)), mp.Cylinder(r, material=mp.air) ] boundary_layers = [mp.PML(dpml)] resolution = 10 fcen = 0.15 df = 0.1 # Bump function def my_src_func(t): if t > 0 and t < 2: return math.exp(-1 / (1 - ((t - 1)**2))) return 0j sources = [mp.Source(src=mp.CustomSource(src_func=my_src_func, end_time=100), component=mp.Ez, center=mp.Vector3(r + 0.1))] symmetries = [mp.Mirror(mp.Y)] sim = mp.Simulation(cell_size=cell, resolution=resolution, geometry=geometry, boundary_layers=boundary_layers, sources=sources, symmetries=symmetries) h = mp.Harminv(mp.Ez, mp.Vector3(r + 0.1), fcen, df) sim.run(mp.after_sources(h), until_after_sources=200) fp = sim.get_field_point(mp.Ez, mp.Vector3(1)) self.assertAlmostEqual(fp, -0.021997617628500023 + 0j, 5 if mp.is_single_precision() else 7)
def test_physical(self): a = 10.0 ymax = 3.0 xmax = 8.0 dx = 2.0 w = 0.30 cell_size = mp.Vector3(xmax, ymax) pml_layers = [mp.PML(ymax / 3.0)] sources = [ mp.Source(src=mp.ContinuousSource(w), component=mp.Ez, center=mp.Vector3(-dx), size=mp.Vector3()) ] sim = mp.Simulation(cell_size=cell_size, resolution=a, boundary_layers=pml_layers, sources=sources, force_complex_fields=True) sim.init_sim() sim.solve_cw(tol=1e-5 if mp.is_single_precision() else 1e-6) p1 = mp.Vector3() p2 = mp.Vector3(dx) amp1 = sim.get_field_point(mp.Ez, p1) amp2 = sim.get_field_point(mp.Ez, p2) ratio = abs(amp1) / abs(amp2) ratio = ratio**2 # in 2d, decay is ~1/sqrt(r), so square to get 1/r fail_fmt = "Failed: amp1 = ({}, {}), amp2 = ({}, {})\nabs(amp1/amp2){} = {}, too far from 2.0" fail_msg = fail_fmt.format(amp1.real, amp1, amp2.real, amp2, "^2", ratio) self.assertTrue(ratio <= 2.12 and ratio >= 1.88, fail_msg)
def test_harminv(self): self.init() self.sim.run(mp.at_beginning(mp.output_epsilon), mp.after_sources(self.h), until_after_sources=300) m1 = self.h.modes[0] self.assertAlmostEqual(m1.freq, 0.118101315147, places=4) self.assertAlmostEqual(m1.decay, -0.000731513241623, places=4) self.assertAlmostEqual(abs(m1.amp), 0.00341267634436, places=4) self.assertAlmostEqual(m1.amp.real, -0.00304951667301, places=4) self.assertAlmostEqual(m1.amp.imag, -0.00153192946717, places=3) v = mp.Vector3(1, 1) fp = self.sim.get_field_point(mp.Ez, v) ep = self.sim.get_epsilon_point(v) places = 5 if mp.is_single_precision() else 7 self.assertAlmostEqual(ep, 11.559999999999999, places=places) self.assertAlmostEqual(fp, -0.08185972142450348, places=places)
def test_integrated_source(self): sources = [ mp.Source(mp.ContinuousSource(1, is_integrated=True), center=mp.Vector3(-2), size=mp.Vector3(y=6), component=mp.Ez) ] sim = mp.Simulation(resolution=20, cell_size=(6, 6), boundary_layers=[mp.PML(thickness=1)], sources=sources, k_point=mp.Vector3()) sim.run(until=30) # field in mid-plane should be nearly constant, # so compute its normalized std. dev. and check << 1 ez = sim.get_array(mp.Ez, center=mp.Vector3(2), size=mp.Vector3(y=6)) std = np.std(ez) / np.sqrt(np.mean(ez**2)) print("std = ", std) self.assertAlmostEqual(std, 0.0, places=4 if mp.is_single_precision() else 8)
def test_epsilon_input_file(self): sim = self.init_simple_simulation() eps_input_fname = 'cyl-ellipsoid-eps-ref.h5' eps_input_dir = os.path.abspath( os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', 'tests')) eps_input_path = os.path.join(eps_input_dir, eps_input_fname) sim.epsilon_input_file = eps_input_path sim.run(until=200) fp = sim.get_field_point(mp.Ez, mp.Vector3(x=1)) places = 6 if mp.is_single_precision() else 7 self.assertAlmostEqual(fp, -0.002989654055823199, places=places) # Test unicode file name for Python 2 if sys.version_info[0] == 2: sim = self.init_simple_simulation( epsilon_input_file=unicode(eps_input_path)) sim.run(until=200) fp = sim.get_field_point(mp.Ez, mp.Vector3(x=1)) self.assertAlmostEqual(fp, -0.002989654055823199)
class TestEigfreq(unittest.TestCase): @unittest.skipIf(mp.is_single_precision(), "double-precision floating point specific test") def test_eigfreq(self): w = 1.2 # width of waveguide r = 0.36 # radius of holes d = 1.4 # defect spacing (ordinary spacing = 1) N = 3 # number of holes on either side of defect sy = 6 # 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 geometry = [mp.Block(size=mp.Vector3(mp.inf,w,mp.inf), material=mp.Medium(epsilon=13))] 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 = 0.25 df = 0.2 src = [mp.Source(mp.GaussianSource(fcen, fwidth=df), component=mp.Hz, center=mp.Vector3(0), size=mp.Vector3(0,0))] sim = mp.Simulation(cell_size=mp.Vector3(sx,sy), force_complex_fields=True, geometry=geometry, boundary_layers=[mp.PML(1.0)], sources=src, symmetries=[mp.Mirror(mp.X, phase=-1), mp.Mirror(mp.Y, phase=-1)], resolution=20) sim.init_sim() eigfreq = sim.solve_eigfreq(tol=1e-6) self.assertAlmostEqual(eigfreq.real, 0.23445413142440263, places=5) self.assertAlmostEqual(eigfreq.imag, -0.0003147775697388, places=5)
def test_transmission_spectrum(self): expected = [ (0.15, 7.218492264696595e-6), (0.1504008016032064, 6.445696315927592e-6), (0.1508016032064128, 5.140949243632777e-6), (0.15120240480961922, 3.6159747936427164e-6), (0.15160320641282563, 2.263940553705969e-6), (0.15200400801603203, 1.4757165844336744e-6), (0.15240480961923844, 1.5491803919142815e-6), (0.15280561122244485, 2.612053246626972e-6), (0.15320641282565126, 4.577504371188737e-6), (0.15360721442885766, 7.1459089162998185e-6), (0.15400801603206407, 9.856622013418823e-6), (0.15440881763527048, 1.2182309227954296e-5), (0.1548096192384769, 1.3647726444709649e-5), (0.1552104208416833, 1.3947420613633674e-5), (0.1556112224448897, 1.303466755716231e-5), (0.1560120240480961, 1.115807915037775e-5), (0.15641282565130252, 8.832335196969796e-6), (0.15681362725450892, 6.743645773127985e-6), (0.15721442885771533, 5.605913756087576e-6), (0.15761523046092174, 5.996668564026961e-6), (0.15801603206412815, 8.209400611614078e-6), (0.15841683366733456, 1.2158641936828497e-5), (0.15881763527054096, 1.73653230513453e-5), (0.15921843687374737, 2.303382576477893e-5), (0.15961923847695378, 2.821180350795834e-5), (0.1600200400801602, 3.200359292911769e-5), (0.1604208416833666, 3.3792624373001934e-5), (0.160821643286573, 3.342171394788991e-5), (0.1612224448897794, 3.1284866146526904e-5), (0.16162324649298582, 2.830022088581398e-5), (0.16202404809619222, 2.5758413657344014e-5), (0.16242484969939863, 2.506899997971769e-5), (0.16282565130260504, 2.7453508915303887e-5), (0.16322645290581145, 3.365089813497114e-5), (0.16362725450901786, 4.370486834112e-5), (0.16402805611222426, 5.689050715055283e-5), (0.16442885771543067, 7.181133157470506e-5), (0.16482965931863708, 8.666168027415369e-5), (0.16523046092184349, 9.961094123261317e-5), (0.1656312625250499, 1.0923388232657953e-4), (0.1660320641282563, 1.1489334204708105e-4), (0.1664328657314627, 1.1698318060032011e-4), (0.16683366733466912, 1.169621456132733e-4), (0.16723446893787552, 1.1714995241571987e-4), (0.16763527054108193, 1.2030783847222252e-4), (0.16803607214428834, 1.2907652919660887e-4), ] self.sim.sources = [ mp.Source(mp.GaussianSource(self.fcen, fwidth=self.df), mp.Ey, mp.Vector3(self.dpml + (-0.5 * self.sx)), size=mp.Vector3(0, self.w)) ] self.sim.symmetries = [mp.Mirror(mp.Y, phase=-1)] freg = mp.FluxRegion(center=mp.Vector3((0.5 * self.sx) - self.dpml - 0.5), size=mp.Vector3(0, 2 * self.w)) trans = self.sim.add_flux(self.fcen, self.df, self.nfreq, freg, decimation_factor=1) self.sim.run(until_after_sources=mp.stop_when_fields_decayed( 50, mp.Ey, mp.Vector3((0.5 * self.sx) - self.dpml - 0.5, 0), 1e-1)) res = zip(mp.get_flux_freqs(trans), mp.get_fluxes(trans)) tol = 1e-8 if mp.is_single_precision() else 1e-10 for e, r in zip(expected, res): self.assertClose(e, r, epsilon=tol)
''' import meep as mp try: import meep.adjoint as mpa except: import adjoint as mpa import numpy as np from autograd import numpy as npa from autograd import tensor_jacobian_product import unittest from enum import Enum from utils import ApproxComparisonTestCase import parameterized _TOL = 1e-6 if mp.is_single_precision() else 1e-14 ## ensure reproducible results rng = np.random.RandomState(9861548) class TestAdjointUtils(ApproxComparisonTestCase): @parameterized.parameterized.expand([ ('1.0_1.0_20_conic', 1.0, 1.0, 20, 0.24, mpa.conic_filter), ('1.0_1.0_23_conic', 1.0, 1.0, 23, 0.24, mpa.conic_filter), ('0.887_1.56_conic', 0.887, 1.56, 20, 0.24, mpa.conic_filter), ('0.887_1.56_conic', 0.887, 1.56, 31, 0.24, mpa.conic_filter), ('0.887_1.56_gaussian', 0.887, 1.56, 20, 0.24, mpa.gaussian_filter), ('0.887_1.56_cylindrical', 0.887, 1.56, 20, 0.24, mpa.cylindrical_filter) ])
def run_test(self, nfreqs): eps = 13 w = 1.2 r = 0.36 d = 1.4 N = 3 sy = 6 pad = 2 dpml = 1 sx = 2 * (pad + dpml + N) + d - 1 cell = mp.Vector3(sx, sy, 0) geometry = [ mp.Block(center=mp.Vector3(), size=mp.Vector3(mp.inf, w, mp.inf), material=mp.Medium(epsilon=eps)) ] 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))) pml_layers = mp.PML(dpml) resolution = 10 fcen = 0.25 df = 0.2 sources = mp.Source(src=mp.GaussianSource(fcen, fwidth=df), component=mp.Hz, center=mp.Vector3()) 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, nfreqs, 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)), decimation_factor=1) sim.run(until=200) d2 = 20 h = 4 vol = mp.Volume(mp.Vector3(0, (0.5 * w) + d2 + (0.5 * h)), size=mp.Vector3(sx - 2 * dpml, h)) result = sim.get_farfields(nearfield, resolution, where=vol) fname = 'cavity-farfield.h5' if nfreqs == 1 else 'cavity-farfield-4-freqs.h5' ref_file = os.path.join(self.data_dir, fname) with h5py.File(ref_file, 'r') as f: # Get reference data into memory ref_ex = mp.complexarray(f['ex.r'][()], f['ex.i'][()]) ref_ey = mp.complexarray(f['ey.r'][()], f['ey.i'][()]) ref_ez = mp.complexarray(f['ez.r'][()], f['ez.i'][()]) ref_hx = mp.complexarray(f['hx.r'][()], f['hx.i'][()]) ref_hy = mp.complexarray(f['hy.r'][()], f['hy.i'][()]) ref_hz = mp.complexarray(f['hz.r'][()], f['hz.i'][()]) tol = 1e-5 if mp.is_single_precision() else 1e-7 self.assertClose(ref_ex, result['Ex'], epsilon=tol) self.assertClose(ref_ey, result['Ey'], epsilon=tol) self.assertClose(ref_ez, result['Ez'], epsilon=tol) self.assertClose(ref_hx, result['Hx'], epsilon=tol) self.assertClose(ref_hy, result['Hy'], epsilon=tol) self.assertClose(ref_hz, result['Hz'], epsilon=tol)
from utils import ApproxComparisonTestCase import jax import jax.numpy as jnp import meep as mp import meep.adjoint as mpa import numpy as onp # The calculation of finite difference gradients requires that JAX be operated with double precision jax.config.update('jax_enable_x64', True) # The step size for the finite difference gradient calculation _FD_STEP = 1e-4 # The tolerance for the adjoint and finite difference gradient comparison _TOL = 0.1 if mp.is_single_precision() else 0.025 # We expect 3 design region monitor pointers (one for each field component) _NUM_DES_REG_MON = 3 mp.verbosity(0) def build_straight_wg_simulation( wg_width=0.5, wg_padding=1.0, wg_length=1.0, pml_width=1.0, source_to_pml=0.5, source_to_monitor=0.1, frequencies=[1 / 1.55],