Repository: DCC-Lab/RayTracing

Issue:
ImagingPath: marginalRays raises exception when no apertureStop
When we want the marginal rays of an `ImagingPath` that has no aperture stop, a `TypeError` is raised. Example:

```python
path = ImagingPath(System4f(10, 10))
path.marginalRays() # Raises TypeError, no field stop
```

Discussion:

Patch:
diff --git a/raytracing/imagingpath.py b/raytracing/imagingpath.py
index b9ee7de..eaea927 100644
--- a/raytracing/imagingpath.py
+++ b/raytracing/imagingpath.py
@@ -188,7 +188,6 @@ class ImagingPath(MatrixGroup):
         """
         return self.chiefRay(y=None)
 
-
     def marginalRays(self, y=0):
         """This function calculates the marginal rays for a height y at object.
         The marginal rays for height y are the rays that hit the upper and lower
@@ -256,6 +255,9 @@ class ImagingPath(MatrixGroup):
 
         """
         (stopPosition, stopDiameter) = self.apertureStop()
+        if stopPosition is None:
+            return None  # No aperture stop -> no marginal rays
+
         transferMatrixToApertureStop = self.transferMatrix(upTo=stopPosition)
         A = transferMatrixToApertureStop.A
         B = transferMatrixToApertureStop.B
@@ -687,10 +689,10 @@ class ImagingPath(MatrixGroup):
         display range : 7
 
         """
-        
+
         displayRange = self.largestDiameter
-        if displayRange == float('+Inf') or displayRange <= 2*self.objectHeight:
-            displayRange = 2*self.objectHeight
+        if displayRange == float('+Inf') or displayRange <= 2 * self.objectHeight:
+            displayRange = 2 * self.objectHeight
 
         conjugates = self.intermediateConjugates()
         if len(conjugates) != 0:
@@ -982,7 +984,7 @@ class ImagingPath(MatrixGroup):
         arrowHeadHeight = self.objectHeight * 0.1
 
         heightFactor = self.objectHeight / yScaling
-        arrowHeadWidth = xScaling * 0.01 * (heightFactor/0.2) ** (3/4)
+        arrowHeadWidth = xScaling * 0.01 * (heightFactor / 0.2) ** (3 / 4)
 
         axes.arrow(
             self.objectPosition,
@@ -1015,7 +1017,7 @@ class ImagingPath(MatrixGroup):
             arrowHeadHeight = arrowHeight * 0.1
 
             heightFactor = arrowHeight / yScaling
-            arrowHeadWidth = xScaling * 0.01 * (heightFactor/0.2) ** (3/4)
+            arrowHeadWidth = xScaling * 0.01 * (heightFactor / 0.2) ** (3 / 4)
 
             axes.arrow(
                 imagePosition,
@@ -1086,7 +1088,7 @@ class ImagingPath(MatrixGroup):
             center = z + pupilPosition
             (xScaling, yScaling) = self.axesToDataScale(axes)
             heightFactor = halfHeight * 2 / yScaling
-            width = xScaling * 0.01 / 2 * (heightFactor/0.2) ** (3/4)
+            width = xScaling * 0.01 / 2 * (heightFactor / 0.2) ** (3 / 4)
 
             axes.add_patch(patches.Polygon(
                 [[center - width, halfHeight],


Test patch:
diff --git a/raytracing/tests/testsImagingPath.py b/raytracing/tests/testsImagingPath.py
index be8f0e1..6590fe8 100644
--- a/raytracing/tests/testsImagingPath.py
+++ b/raytracing/tests/testsImagingPath.py
@@ -61,6 +61,10 @@ class TestImagingPath(unittest.TestCase):
         chiefRay = path.chiefRay()
         self.assertIsNone(chiefRay)
 
+    def testMarginalRaysNoApertureStop(self):
+        path = ImagingPath(System4f(10, 10))
+        self.assertIsNone(path.marginalRays())
+
     def testMarginalRaysIsImaging(self):
         path = ImagingPath(System4f(10, 10))
         path.append(Aperture(10))