def test_conic_surface(): # Prove that with a conic surface we can focus parallel rays perfectly. n1 = 1 n2 = 1.5 f = 1 roc = f * (n2 - n1) / n2 x0s = [-0.2, -0.1, 0, 0.1, 0.2] # There is a formula for this: # https://www.iap.uni - jena.de/iapmedia/de/Lecture/Advanced + Lens + Design1393542000/ALD13_Advanced + Lens + Design + 7 + _ + Aspheres + and +freeforms.pdf # but I obtained it numerically (in demo_conic_surface.py). kappa = 0.55555 f = roc * n2 / (n2 - n1) interface = rt1.FresnelInterface(ri.FixedIndex(n1), ri.FixedIndex(n2)) conic_surface = rt1.Surface(rt1.ConicProfile(roc, kappa), interface=interface) origin = v4hb.stack_xyzw(x0s, 0, -1, 1) vector = v4hb.stack_xyzw(0, 0, 1, 0) detector_surface = rt1.Surface(rt1.PlanarProfile(), matrix=h4t.make_translation(0, 0, f)) surfaces = conic_surface, detector_surface line = rt1.Line(origin, vector) pol = v4hb.cross(line.vector, [0, 1, 0, 0]) ray = rt1.Ray(line, pol, 1, 0, 860e-9, n1) segments = ray.trace_surfaces(surfaces, ['transmitted', 'incident'])[0] assert len(segments) == 3 xy = segments[-1].ray.line.origin[..., :2] # The focusing is close (f number 2.5) but not quite perfect due to errors in the intersection solver. assert np.allclose(xy, 0, atol=2e-6)
def test_tracing(): normal = v4h.to_vector((0, 0, -1)) constant = 0 surface = sdb.Plane(normal, constant) n0 = 1 n0fun = ri.FixedIndex(n0) n1 = 1.5 n1fun = ri.FixedIndex(n1) element = rt2.Element(surface, rt2.UniformIsotropic(n1fun), rt2.FresnelInterface()) #assert rt2.get_deflector(element, np.asarray((1, 2, 3, 1))) is deflector assembly = rt2.Assembly(element.surface, [element], rt2.UniformIsotropic(n0fun)) assert _get_transformed_element(assembly, v4h.to_point((1, 2, -1))) is None affine_surface = _get_transformed_element(assembly, v4h.to_point((1, 2, 1))).surface lamb = 800e-9 incident_ray = rt2.make_ray(assembly, 1., 2, -1, 0, 1, 1, 1, 0, 0, lamb) epsilon = 1e-9 length, deflected_rays = _process_ray(assembly, incident_ray, dict(epsilon=epsilon, t_max=1e9, max_steps=100)) assert (2**0.5 - epsilon) <= length <= (2**0.5 + epsilon) (rp, rs), (tp, ts) = functions.calc_fresnel_coefficients(n0, n1, abs(dot(incident_ray.line.vector, normal))) assert 0 <= npscalar.getsdb(surface, deflected_rays[0].line.origin) <= epsilon assert np.array_equal(deflected_rays[0].line.vector, normalize(v4h.to_vector((0, 1, -1, 0)))) assert np.isclose(deflected_rays[0].flux, rs**2) vy = 2**-0.5*n0/n1 assert 0 >= npscalar.getsdb(surface, deflected_rays[1].line.origin) >= -epsilon assert np.allclose(deflected_rays[1].line.vector, (0, vy, (1 - vy**2)**0.5, 0)) assert np.isclose(deflected_rays[1].flux, ts**2*n1/n0)
def test_Train_make_singlet(): n = 3 f = 10 shapes = np.asarray((-1, 0, 1)) d = 0.1 for ne in (1, 1.5): for shape in shapes: train = trains.Train.design_singlet(ri.FixedIndex(n), f, shape, d, 0.01, ne=ri.FixedIndex(ne)) assert np.allclose(train.get_focal_lengths() / ne, f)
def test_beam_tracing(qtbot): n = 1.5 lamb = 860e-9 w = 80e-3 f = 100e-3 waist = 20e-6 k = 2*np.pi/lamb roc, center_thickness = paraxial.design_thick_spherical_transform_lens(n, w, f) lens_surfaces = rt1.make_spherical_lens_surfaces(roc, -roc, center_thickness, ri.FixedIndex(n)) z_fp = center_thickness/2 + w beam = asbt1.Beam(asbp.PlaneProfile.make_gaussian(lamb, 1, waist, 160e-6, 64, z_waist=-z_fp)) surface1 = rt1.Surface(rt1.PlanarProfile(), otk.h4t.make_translation(0, 0, z_fp)) surfaces = lens_surfaces + (surface1,) beam_segments = asbt1.trace_surfaces(beam, surfaces, ['transmitted', 'transmitted', None]) origin = beam.to_global(v4hb.stack_xyzw([0, -waist, waist, 0, 0], [0, 0, 0, -waist, waist], -z_fp, 1)) vector_local = v4hb.normalize(v4hb.stack_xyzw([0, 2/waist, -2/waist, 0, 0], [0, 0, 0, 2/waist, -2/waist], k, 0)) vector = beam.to_global(vector_local) line = otk.rt1._lines.Line(origin, vector) polarization = v4hb.normalize(v4hb.cross(vector, [1,0,0,0])) ray_segments = otk.rt1._raytrace.Ray(line, polarization, 1, 0, lamb, 1).trace_surfaces(surfaces, ['transmitted', 'transmitted', 'incident']) # TODO resurrect # segments = [asbp.BeamRaySegment.combine(bs, rs) for bs, rs in zip(beam_segments, ray_segments)] # # widget = asbp.MultiProfileWidget.plot_segments(segments) # qtbot.addWidget(widget) # for n in range(len(widget.entries)): # widget.set_index(n)
def test_refraction(): """Test collimation of a point source by a spherical refracting surface.""" n1 = 1.5 n2 = 3 f = 100 r0 = np.asarray((100, 20, 300, 1)) interface = rt1.FresnelInterface(ri.FixedIndex(n1), ri.FixedIndex(n2)) s = rt1.Surface(rt1.SphericalProfile(f * (n2 - n1)), otk.h4t.make_translation(*r0[:3]), interface=interface) origin = r0 + (0, 0, -f * n1, 0) line = rt1.Line(origin, v4hb.normalize((0.001, 0.001, 1, 0))) pol = v4hb.cross(line.vector, [0, 1, 0, 0]) ray = rt1.Ray(line, pol, 0, 860e-9, n1) segments = ray.trace_surfaces((s, ), ('transmitted', ))[0] assert len(segments) == 2 assert segments[-1].ray.n == n2 assert np.allclose(segments[-1].ray.line.vector, (0, 0, 1, 0))
def test_Train_make_singlet_transform2(): n = 1.5 f = 10 shapes = np.asarray((-1, 0, 1)) d = 0.1 for shape in shapes: train = trains.Train.make_singlet_transform2(ri.FixedIndex(n), f, shape, d, 0.01) assert np.allclose(train.get_focal_lengths(), f)
def test_make_square_element_train(): index = ri.FixedIndex(1.5) train = trains.Singlet.from_focal_length(100e-3, index, 5e-3, 12.5e-3, 0) element = rt2.to_rectangular_array_element( train, [sdb.RectangularArrayLevel.make(12.5e-3, 3)], (1, 2, 3)) assert element.medium == rt2.UniformIsotropic(index) front = element.surface.surfaces[0] assert front.sagfun.unit.roc == train.surfaces[0].roc
def test_Train_principal_planes(): n = 1.5 f = 0.5 shape = 0.1 thickness = 0.01 l = trains.Train.design_singlet(ri.FixedIndex(n), f, shape, thickness, 0.01) ppb, ppf = l.get_principal_planes() _, ppb_, ppf_ = paraxial.calc_thick_spherical_lens(n, l.interfaces[0].roc, l.interfaces[1].roc, thickness) assert np.isclose(ppb, ppb_) assert np.isclose(ppf, ppf_)
def test_Train_make_singlet_transform1(): n = 1.5 ws = 1, 2 f = 10 l = trains.Train.make_singlet_transform1(ri.FixedIndex(n), ws, f, 0.01) testing.assert_allclose(l.get_focal_lengths(), (f, f)) assert len(l.spaces) == 3 assert np.isclose(l.spaces[0], ws[0]) assert np.isclose(l.spaces[2], ws[1]) testing.assert_allclose(l.get_focal_lengths(), (f, f)) l2 = l.pad_to_transform() testing.assert_allclose(l2.get_working_distances(), (0, 0), atol=2e-15)
def test_hyperbolic_lens(): # Prove that with a conic surface we can focus parallel rays perfectly. n1 = 1 n2 = 1.5 f = 1 roc = f*(n2 - n1)/n2 x0s = [-0.2, -0.1, 0., 0.1, 0.2] # There is a formula for this: # https://www.iap.uni - jena.de/iapmedia/de/Lecture/Advanced + Lens + Design1393542000/ALD13_Advanced + Lens + Design + 7 + _ + Aspheres + and +freeforms.pdf # but I obtained it numerically (in demo_conic_surface.py). kappa = 0.55555 # 0.55555 f = roc*n2/(n2 - n1) surface = sdb.ZemaxConic(roc, 0.3, 1, kappa) element = rt2.Element(surface, rt2.UniformIsotropic(ri.FixedIndex(n2)), rt2.perfect_refractor) assembly = rt2.Assembly(surface, [element], rt2.UniformIsotropic(ri.FixedIndex(n1))) sphere_trace_kwargs = dict(epsilon=1e-9, t_max=1e9, max_steps=100) focus = (0, 0, f, 1) for x0 in x0s: ray = rt2.make_ray(assembly, x0, 0, -1, 0, 0, 1, 1, 0, 0, 800e-9) segments = rt2.nonseq_trace(assembly, ray, sphere_trace_kwargs).flatten() assert len(segments) == 2 assert norm(segments[1].ray.line.pass_point(focus)[1].origin - focus) < 1e-6
def test_make_spherical_lens_surfaces(): roc1 = 100 roc2 = 50 d = 30 n = 1.5 f, h1, h2 = paraxial.calc_thick_spherical_lens(n, roc1, -roc2, d) surfaces = rt1.make_spherical_lens_surfaces(roc1, -roc2, d, ri.FixedIndex(n)) line = rt1.Line((0, 0, -f + h1 - d / 2, 1), v4hb.normalize((1e-4, 1e-4, 1, 0))) pol = v4hb.cross(line.vector, [0, 1, 0, 0]) ray = rt1.Ray(line, pol, 0, 860e-9, 1) segments = ray.trace_surfaces(surfaces, ['transmitted'] * 2)[0] assert len(segments) == 3 assert segments[1].ray.n == n assert np.allclose(segments[-1].ray.line.vector, (0, 0, 1, 0))
def test_Interface_calc_mask(): n1 = ri.vacuum n2 = ri.FixedIndex(1.5) roc = 0.1 lamb = 530e-9 rho = 0.05 interface = trains.Interface(n1, n2, roc, 10e-3) f, gradf = interface.calc_mask(lamb, rho, True) sag = functions.calc_sphere_sag(roc, rho) k = 2 * np.pi / lamb deltan = n1(lamb) - n2(lamb) assert np.isclose(f, np.exp(1j * sag * k * deltan)) grad_sag = functions.calc_sphere_sag(roc, rho, True) assert np.isclose(gradf, 1j * k * deltan * grad_sag * f)
def propagate(self): lamb = self.wavelength_widget.value() * 1e-9 waist0 = self.source_diameter_widget.value() / 2 * 1e-3 num_points = self.num_points rs_waist = np.asarray((self.source_x_widget.value() * 1e-3, self.source_y_widget.value() * 1e-3)) source_z = self.source_z_widget.value() * 1e-3 roc1 = self.roc1_widget.value() * 1e-3 roc2 = self.roc2_widget.value() * 1e-3 d = self.thickness_widget.value() * 1e-3 n = ri.FixedIndex(self.n_widget.value()) # These are calculated by lens update. f = self.f w1 = self.w1 w2 = self.w2 r0_centers = rs_waist q0_centers = (0, 0) k = 2 * np.pi / lamb r0_support = waist0 * self.waist0_factor # *#(np.pi*num_points)**0.5*waist0 x0, y0 = asbp.calc_xy(r0_support, num_points, r0_centers) # Create input beam and prepare for propagation to first surface. Er0 = asbp.calc_gaussian(k, x0, y0, waist0, r0s=rs_waist) profile0 = asbp.PlaneProfile( lamb, 1, source_z, r0_support, Er0, asbp.calc_gradxyE(r0_support, Er0, q0_centers), r0_centers, q0_centers) b0 = asbt1.Beam(profile0) s1 = rt1.Surface(rt1.SphericalProfile(roc1), otk.h4t.make_translation(0, 0, w1), interface=rt1.PerfectRefractor(ri.air, n)) s2 = rt1.Surface(rt1.SphericalProfile(-roc2), otk.h4t.make_translation(0, 0, w1 + d), interface=rt1.PerfectRefractor(n, ri.air)) s3 = rt1.Surface(rt1.PlanarProfile(), otk.h4t.make_translation(0, 0, w1 + d + w2)) segments = asbt1.trace_surfaces( b0, (s1, s2, s3), ('transmitted', 'transmitted', None))[0] b1_incident = segments[0].beams[1] b1_refracted = segments[1].beams[0] b1_plane = segments[1].planarized_beam b2_incident = segments[1].beams[1] b2_refracted = segments[2].beams[0] b2_plane = segments[2].planarized_beam b3 = segments[2].beams[1] # b1_incident = b0.propagate(s1, self.kz_mode) # b1_refracted = b1_incident.refract(s1, self.kz_mode) # b1_plane = b1_refracted.planarize(kz_mode=self.kz_mode, invert_kwargs=self.invert_kwargs) # b2_incident = b1_plane.propagate(s2, self.kz_mode) # b2_refracted = b2_incident.refract(s2, self.kz_mode) # b2_plane = b2_refracted.planarize(kz_mode=self.kz_mode, invert_kwargs=self.invert_kwargs) # b3 = b2_plane.propagate(s3, kz_mode=self.kz_mode) self.b0 = b0 self.b1_incident = b1_incident self.b1_refracted = b1_refracted self.b1_plane = b1_plane self.b2_incident = b2_incident self.b2_plane = b2_plane self.b3 = b3 waist3 = f * lamb / (np.pi * waist0) self.b3_scale = waist3 / waist0 self.update_plots()
def make(cls, x): if isinstance(x, ri.Index): return UniformIsotropic(x) else: n = float(x) return UniformIsotropic(ri.FixedIndex(n))
def test_pad_to_half_transform(): l = trains.Train.make_singlet_transform2(ri.FixedIndex(1.5), 0.5, 0.1, 0.01, 0.01) fp = 1 lp = l.pad_to_half_transform(f=fp) assert np.allclose((lp + lp.reverse()).get_focal_lengths(), fp)