z.SetSolve( 6, # surface number 0, # solve code for curvature 11, # solve type code for f/# 3.5 # desired f/# ) # Let's add an extra constraint. We'll make the curvatures on the # faces of the central element equal. We can insert a pickup solve # like this: central_front_face = model[3] central_rear_face = model[4] central_rear_face.curvature = -central_front_face.curvature.linked() # Load a merit function from another zemax file z.LoadMerit("C:\\Program Files\\ZEMAX\\Samples\\Short course\\sc_cooke2.zmx") # Insert a flat, glass window in front of the lens model.insert_new(1, surface.Standard, "Window", thickness=1.0, glass="BK7") model.insert_new(2, surface.Standard, thickness=10.0) print("Optimising ....") print("Initial merit func = %g" % z.Optimize(-1)) print("Final merit func = %g" % z.Optimize()) # Push the lens from the Zemax server into the display. # The option "allow extensions to push lenses" should be enabled in # Zemax preferences. z.GetUpdate() z.PushLens()
class CoordinateReturn(unittest.TestCase): def setUp(self): self.z = Connection() self.z.NewLens() self.model = SurfaceSequence(self.z, empty=True) self.first, self.last = build_coord_break_sequence(self.model) def testZemaxCoordinateReturn(self): cb = self.model.append_new(surface.CoordinateBreak) return_surf = cb.get_surf_num() self.z.SetSurfaceData(return_surf, 81, self.first) self.z.SetSurfaceData(return_surf, 80, 3) # orientation + offset self.z.GetUpdate() self.coord_return_common_tests(return_surf) def testLibraryCoordinateReturn(self): cb = self.model.append_new(surface.CoordinateBreak) cb.return_to(self.model[self.first]) self.z.GetUpdate() self.coord_return_common_tests(cb.get_surf_num()) # To unset the coordinate return, pass None (has no effect here) cb.return_to(None) # unset coordinate return status def testFull(self): return_surf = return_to_coordinate_frame(self.model, self.first, self.last) self.z.GetUpdate() self.coord_return_common_tests(return_surf) def testOmitZeroThicknesses(self): self.z.GetUpdate() return_surf = return_to_coordinate_frame(self.model, self.first, self.last, include_null_transforms=False) self.z.GetUpdate() self.coord_return_common_tests(return_surf) def testWithCursor(self): insert_point = self.last insertion_point_sequence = count(insert_point+1) def factory(): return self.model.insert_new(next(insertion_point_sequence), surface.CoordinateBreak) self.z.GetUpdate() return_surf = return_to_coordinate_frame(self.model, self.first, self.last, include_null_transforms=False, factory=factory) self.z.GetUpdate() self.coord_return_common_tests(return_surf) def testWithAppend(self): def factory(): return self.model.append_new(surface.CoordinateBreak) self.z.GetUpdate() return_surf = return_to_coordinate_frame(self.model, self.first, self.last, include_null_transforms=False, factory=factory) self.z.GetUpdate() self.coord_return_common_tests(return_surf) def coord_return_common_tests(self, return_surf): first_rot, first_offset = self.z.GetGlobalMatrix(self.first) last_rot, last_offset = self.z.GetGlobalMatrix(self.last) return_rot, return_offset = self.z.GetGlobalMatrix(return_surf + 1) # check coordinate frames are identical self.assertAlmostEqual(abs(first_rot - return_rot).max(), 0) self.assertAlmostEqual(abs(first_offset - return_offset).max(), 0) # check we have finite rotation matrices self.assertNotAlmostEqual(abs(first_rot).max(), 0) # check that first and last frames differ self.assertNotAlmostEqual(abs(first_rot - last_rot).max(), 0) self.assertNotAlmostEqual(abs(first_offset - last_offset).max(), 0)
class RayCoordinates(unittest.TestCase): marginal_ray_solve_pupil_coordinate = 0.7 tracing_accuracy = 4 # expected accuracy in decimal places def setUp(self): self.z = Connection() self.z.NewLens() self.model = SurfaceSequence(self.z) self.system = SystemConfig(self.z) self.system.rayaimingtype = 0 self.model[0].thickness = 10.0 # insert fold mirror self.model.append_new(surface.CoordinateBreak, rotate_y=40.0, rotate_z=10.0) self.model.append_new(surface.Standard, glass="MIRROR") cb = self.model.append_new(surface.CoordinateBreak, thickness=-20.0) cb.rotate_x.align_to_chief_ray() cb.rotate_y.align_to_chief_ray() front = self.model.append_new(surface.Standard, curvature=-0.05, glass="BK7", thickness=-1.0) back = self.model.append_new(surface.Standard, curvature=-front.curvature.linked()) self.z.SetSystemAper(3, front.get_surf_num(), 2.5) back.thickness.focus_on_next(self.marginal_ray_solve_pupil_coordinate) self.z.GetUpdate() def testFocus(self): image = self.model[-1] chief = image.get_ray_intersect() marginal = image.get_ray_intersect( (0, 0), (0, self.marginal_ray_solve_pupil_coordinate), 0) self.assertAlmostEqual(abs(marginal.intersect - chief.intersect).max(), 0.0) def testDirectTracing(self): """Verify that we can launch rays using normalised pupil coordinates and local surface cartesian coordinates, with consistent results.""" pc = (0.3, 0.5) # normalised pupil coordinate under test image = self.model[-1] # find ray intersection on image plane (status, vigcode, im_intersect, im_exit_cosines, normal, intensity) = image.get_ray_intersect((0, 0), pc) for surf in self.model: # get ray intersection on surface (status, vigcode, surf_intersect, exit_cosines, normal, intensity) = surf.get_ray_intersect((0, 0), pc) # Launch ray directly using the obtained origin and exit cosines. # GetTraceDirect launches a ray from startsurf coordinate # frame, but the ray does not interact with startsurf. (status, vigcode, intersect, cosines, normal, intensity) = self.z.GetTraceDirect(0, 0, surf.get_surf_num(), image.get_surf_num(), surf_intersect, exit_cosines) # verify that the ray is the same as obtained with # normalised pupil coordinates on the image plane self.assertAlmostEqual(abs(intersect - im_intersect).max(), 0.0, self.tracing_accuracy) self.assertAlmostEqual(abs(cosines - im_exit_cosines).max(), 0.0, self.tracing_accuracy) if surf.id != image.id: self.assertNotAlmostEqual( abs(surf_intersect - im_intersect).max(), 0.0, self.tracing_accuracy) def testMatrixCoordinateTransforms(self): """Check we can acquire and use global transformation matrices. Make each surface the coordinate global reference in turn. For each iteration check we can recover the original global reference of each surface by applying the inverse of the new global reference.""" def trans_mat(rotation, offset): m = numpy.zeros((4, 4), float) m[0:3, 0:3] = rotation m[0:3, 3] = offset m[3, 3] = 1.0 return numpy.matrix(m) surf_ids = range(len(self.model)) initial_global_ref = self.system.globalrefsurf initial_surface_coord_frames = [ trans_mat(*self.z.GetGlobalMatrix(i)) for i in surf_ids] for i in surf_ids: if isinstance(self.model[i], surface.CoordinateBreak): # coordinate breaks as global reference surfaces give # unexpected results continue self.system.globalrefsurf = i # find inverse transformation trans = initial_surface_coord_frames[i].I self.z.GetUpdate() for j in surf_ids: new_frame = trans_mat(*self.z.GetGlobalMatrix(j)) # calc_frame = numpy.dot(trans, # initial_surface_coord_frames[j]) calc_frame = trans * initial_surface_coord_frames[j] self.assertAlmostEqual(abs(new_frame - calc_frame).max(), 0) def testCheckRayTraceResults(self): pc = (0.3, 0.5) # normalised pupil coordinate under test for surf in self.model: n = surf.get_surf_num() # get ray intersection on surface in local coordinates # (status, vigcode, intersect, exit_cosines, normal, # intensity) = surf.get_ray_intersect((0,0), pc) ray = surf.get_ray_intersect((0, 0), pc) # compare with values obtained from operands for val, op in zip(ray.intersect, ("REAX", "REAY", "REAZ")): opval = self.z.OperandValue(op, n, 0, 0.0, 0.0, pc[0], pc[1]) self.assertAlmostEqual(opval, val, places=5) # get ray intersection on surface in global coordinates # (status, vigcode, intersect_gl, exit_cosines, normal, # intensity) = surf.get_ray_intersect((0,0), pc, _global=True) glray = surf.get_ray_intersect((0, 0), pc, _global=True) # compare with direct global coordinates from operands for val, op in zip(glray.intersect, ("RAGX", "RAGY", "RAGZ")): opval = self.z.OperandValue(op, n, 0, 0.0, 0.0, pc[0], pc[1]) self.assertAlmostEqual(opval, val, self.tracing_accuracy)
class SurfaceSequenceManipulate(unittest.TestCase): """Check that semantics of SurfaceSequence are close to Python list type. """ def setUp(self): self.z = Connection() self.z.NewLens() self.model = SurfaceSequence(self.z, empty=True) self.model[0].comment.value = "OBJ" self.model[-1].comment.value = "IMG" self._list = ["OBJ", "IMG"] def verifyIdentical(self): self.z.GetUpdate() self.assertEqual(len(self._list), len(self.model)) for a, s in zip(self._list, self.model): self.assertEqual(a, s.comment.value) def testInit(self): self.verifyIdentical() def testInsert(self): self.model.insert_new(1, surface.Standard, "Inserted 1") self._list.insert(1, "Inserted 1") self.model.insert_new(-1, surface.Standard, "Inserted -1") self._list.insert(-1, "Inserted -1") self.verifyIdentical() def testDelete(self): self.model.insert_new(1, surface.Standard, "Inserted 1") self._list.insert(1, "Inserted 1") self.model.insert_new(-1, surface.Standard, "Inserted -1") self._list.insert(-1, "Inserted -1") self.verifyIdentical() del self.model[1] del self._list[1] self.verifyIdentical() del self.model[-2] del self._list[-2] self.verifyIdentical() def testGetItem(self): self.model.insert_new(1, surface.Standard, "Inserted 1") self._list.insert(1, "Inserted 1") for i in range(len(self.model)): self.assertEqual(self.model[i].comment.value, self._list[i]) self.assertEqual(self.model[-i].comment.value, self._list[-i]) def testAppendItem(self): # Here the behaviour differs. The surface is inserted before # the last (image) surface self.model.insert_new(1, surface.Standard, "Inserted 1") self._list.insert(1, "Inserted 1") self.model.append_new(surface.Standard, "Appended") self._list.insert(-1, "Appended") self.verifyIdentical() def testIndexing(self): new_surf = self.model.insert_new(1, surface.Grating, "Inserted 1") indexed_surf = self.model[1] self.assertEqual(new_surf.id, indexed_surf.id) # check that model retrieves surface object with correct class self.assertEqual(new_surf.__class__, indexed_surf.__class__)