def test_pol(self): # polarization not a string with self.assertRaises(ValueError): Simulation(self.omega, self.eps_r, self.dl, self.NPML, 5) # polarization not the right string with self.assertRaises(ValueError): Simulation(self.omega, self.eps_r, self.dl, self.NPML, 'WrongPolarization')
def test_dl(self): # negative dl with self.assertRaises(ValueError): Simulation(self.omega, self.eps_r, -self.dl, self.NPML, self.pol) # list of dl with self.assertRaises(ValueError): Simulation(self.omega, self.eps_r, [1e-4, 1e-5], self.NPML, self.pol)
def test_eps(self): # negative epsilon with self.assertRaises(ValueError): Simulation(self.omega, -self.eps_r, self.dl, self.NPML, self.pol) # list epsilon instead of numpy array with self.assertRaises(ValueError): Simulation(self.omega, list(self.eps_r), self.dl, self.NPML, self.pol)
def test_freq(self): # negative frequency with self.assertRaises(ValueError): Simulation(-self.omega, self.eps_r, self.dl, self.NPML, self.pol) # list of frequencies with self.assertRaises(ValueError): Simulation([100, 200, 300], self.eps_r, self.dl, self.NPML, self.pol)
def test_NPML(self): # NPML a number with self.assertRaises(ValueError): Simulation(self.omega, self.eps_r, self.dl, 10, self.pol) # NPML too many elements with self.assertRaises(ValueError): Simulation(self.omega, self.eps_r, self.dl, [10, 10, 10], self.pol) # NPML larger than domain with self.assertRaises(ValueError): Simulation(self.omega, self.eps_r, self.dl, [200, 200], self.pol)
def test_born_newton(self): """Tests whether born and newton methods get the same result""" n0 = 3.4 omega = 2*np.pi*200e12 dl = 0.01 chi3 = 2.8E-18 width = 1 L = 5 L_chi3 = 4 width_voxels = int(width/dl) L_chi3_voxels = int(L_chi3/dl) Nx = int(L/dl) Ny = int(3.5*width/dl) eps_r = np.ones((Nx, Ny)) eps_r[:, int(Ny/2-width_voxels/2):int(Ny/2+width_voxels/2)] = np.square(n0) nl_region = np.zeros(eps_r.shape) nl_region[int(Nx/2-L_chi3_voxels/2):int(Nx/2+L_chi3_voxels/2), int(Ny/2-width_voxels/2):int(Ny/2+width_voxels/2)] = 1 simulation = Simulation(omega, eps_r, dl, [15, 15], 'Ez') simulation.add_mode(n0, 'x', [17, int(Ny/2)], width_voxels*3) simulation.setup_modes() simulation.add_nl(chi3, nl_region, eps_scale=True, eps_max=np.max(eps_r)) srcval_vec = np.logspace(1, 3, 3) pwr_vec = np.array([]) T_vec = np.array([]) for srcval in srcval_vec: simulation.setup_modes() simulation.src *= srcval # Newton simulation.solve_fields_nl(solver_nl='newton') E_newton = simulation.fields["Ez"] # Born simulation.solve_fields_nl(solver_nl='born') E_born = simulation.fields["Ez"] # More solvers (if any) should be added here with corresponding calls to assert_allclose() below assert_allclose(E_newton, E_born, rtol=1e-3)
def test_chi3(self): """Tests whether we get a nonlinear phase shift (self phase modulation) which agrees with analytical predictions""" # Set simulation parameters n0 = 3.4 omega = 2 * pi * 200e12 dl = 0.01 chi3 = 2.8E-18 width = 1 # WG width L = 5 # WG length L_chi3 = 4 # WG nonlinear length # Convert to voxels width_voxels = int(width / dl) L_chi3_voxels = int(L_chi3 / dl) Nx = int(L / dl) Ny = int(3.5 * width / dl) # Setup eps_r = ones((Nx, Ny)) eps_r[:, int(Ny / 2 - width_voxels / 2):int(Ny / 2 + width_voxels / 2)] = square(n0) nl_region = zeros(eps_r.shape) nl_region[int(Nx / 2 - L_chi3_voxels / 2):int(Nx / 2 + L_chi3_voxels / 2), int(Ny / 2 - width_voxels / 2):int(Ny / 2 + width_voxels / 2)] = 1 simulation = Simulation(omega, eps_r, dl, [15, 15], 'Ez') simulation.add_mode(n0, 'x', [17, int(Ny / 2)], width_voxels * 3) simulation.setup_modes() simulation.solve_fields() # Probe field from linear simulation to get phase fld0 = simulation.fields['Ez'][20, int(Ny / 2)] fld1 = simulation.fields['Ez'][Nx - 20, int(Ny / 2)] T_linear = fld1 / fld0 # Set nonlinear functions kerr_nonlinearity = lambda e: 3 * chi3 / square(simulation.L0 ) * square(abs(e)) dkerr_de = lambda e: 3 * chi3 / square(simulation.L0) * conj(e) # Sweep source power and record nonlinear phase accumulation srcval_vec = logspace(1, 3, 3) pwr_vec = array([]) T_vec = array([]) for srcval in srcval_vec: simulation.setup_modes() simulation.src *= srcval simulation.solve_fields_nl(kerr_nonlinearity, nl_region, dnl_de=dkerr_de, timing=False, averaging=True, Estart=None, solver_nl='newton') fld0 = simulation.fields['Ez'][20, int(Ny / 2)] fld1 = simulation.fields['Ez'][Nx - 20, int(Ny / 2)] T_vec = append(T_vec, fld1 / fld0) pwr = simulation.flux_probe('x', [Nx - 20, int(Ny / 2)], width_voxels * 3) pwr_vec = append(pwr_vec, pwr) # Analytically calculate the expected nonlinear phase accumulation n2 = 12 * square(pi) * chi3 * 1e4 / square(n0) n2 *= 1e-4 / square(simulation.L0) width = dl * width_voxels height = width Aeff = width * height L = dl * L_chi3_voxels gamma_spm = (omega / 299792458 * simulation.L0) * n2 / Aeff P = pwr_vec * height # Power Phi_fdfd = -unwrap(angle(T_vec) - angle(T_linear)) / pi # Nonlinear phase in FDFD Phi_analytic = ( pwr_vec * height) * L * gamma_spm / pi # Analytic nonlinear phase # If our simulation is correct, these values should be equal assert_allclose(Phi_fdfd, Phi_analytic, rtol=1e-3)
def test_flux(self): """Tests whether we can reduce the mesh resolution and get the same flux_probe output""" omega = 2 * pi * 200e12 dl = 0.01 eps_r = ones((300, 100)) eps_r[:, 40:60] = 12.25 NPML = [15, 15] simulation1 = Simulation(omega, eps_r, dl, NPML, 'Ez') simulation1.add_mode(3.5, 'x', [20, 50], 60, scale=1) simulation1.setup_modes() simulation1.solve_fields() flux1 = simulation1.flux_probe('x', [150, 50], 60) omega = 2 * pi * 200e12 dl = 0.005 eps_r = ones((600, 200)) eps_r[:, 80:120] = 12.25 NPML = [15, 15] simulation2 = Simulation(omega, eps_r, dl, NPML, 'Ez') simulation2.add_mode(3.5, 'x', [20, 100], 120, scale=1) simulation2.setup_modes() simulation2.solve_fields() flux2 = simulation2.flux_probe('x', [300, 100], 120) assert_allclose(flux1, flux2, rtol=1e-3)