Repository: DCC-Lab/RayTracing

Issue:
EigenModes of LaserPath fails with exception when C = 0
When we create a `LaserPath` and its C component is 0, we have a division by 0, which raises an exception. We should check if the laser path has power (`self.hasPower`) before and return `(None, None)`  (maybe?) if not. We then need to change other methods, like `laserModes` and `display`.

Discussion:

Patch:
diff --git a/raytracing/laserpath.py b/raytracing/laserpath.py
index 4f74727..edcf1b2 100644
--- a/raytracing/laserpath.py
+++ b/raytracing/laserpath.py
@@ -1,6 +1,7 @@
 from .matrixgroup import *
 from .imagingpath import *
 
+
 class LaserPath(MatrixGroup):
     """LaserPath: the main class of the module for coherent
     laser beams: it is the combination of Matrix() or MatrixGroup()
@@ -17,6 +18,7 @@ class LaserPath(MatrixGroup):
     is set to indicate it, but it will propagate nevertheless
     and without diffraction due to that aperture.
     """
+
     def __init__(self, elements=None, label=""):
         self.inputBeam = None
         self.isResonator = False
@@ -33,11 +35,14 @@ class LaserPath(MatrixGroup):
         round trip: you will need to duplicate elements in reverse
         and append them manually. 
         """
+        if not self.hasPower:
+            return None, None
+
         b = self.D - self.A
-        sqrtDelta = cmath.sqrt(b*b + 4.0 *self.B *self.C)
-        
-        q1 = (- b + sqrtDelta)/(2.0*self.C)
-        q2 = (- b - sqrtDelta)/(2.0*self.C)
+        sqrtDelta = cmath.sqrt(b * b + 4.0 * self.B * self.C)
+
+        q1 = (- b + sqrtDelta) / (2.0 * self.C)
+        q2 = (- b - sqrtDelta) / (2.0 * self.C)
 
         return (GaussianBeam(q=q1), GaussianBeam(q=q2))
 
@@ -49,10 +54,10 @@ class LaserPath(MatrixGroup):
 
         (q1, q2) = self.eigenModes()
         q = []
-        if q1.isFinite:
+        if q1 is not None and q1.isFinite:
             q.append(q1)
 
-        if q2.isFinite:
+        if q2 is not None and q2.isFinite:
             q.append(q2)
 
         return q
@@ -133,12 +138,11 @@ class LaserPath(MatrixGroup):
         for element in self.elements:
             if isinstance(element, Space):
                 for i in range(N):
-                    highResolution.append(Space(d=element.L/N, 
+                    highResolution.append(Space(d=element.L / N,
                                                 n=element.frontIndex))
             else:
                 highResolution.append(element)
 
-
         beamTrace = highResolution.trace(beam)
         (x, y) = self.rearrangeBeamTraceForPlotting(beamTrace)
         axes.plot(x, y, 'r', linewidth=1)
@@ -166,11 +170,11 @@ class LaserPath(MatrixGroup):
             position = beam.z + relativePosition
             size = beam.waist
 
-            axes.arrow(position, size+arrowSize, 0, -arrowSize,
-                width=0.1, fc='g', ec='g',
-                head_length=arrowHeight, head_width=arrowWidth,
-                length_includes_head=True)
-            axes.arrow(position, -size-arrowSize, 0, arrowSize,
-                width=0.1, fc='g', ec='g',
-                head_length=arrowHeight, head_width=arrowWidth,
-                length_includes_head=True)
+            axes.arrow(position, size + arrowSize, 0, -arrowSize,
+                       width=0.1, fc='g', ec='g',
+                       head_length=arrowHeight, head_width=arrowWidth,
+                       length_includes_head=True)
+            axes.arrow(position, -size - arrowSize, 0, arrowSize,
+                       width=0.1, fc='g', ec='g',
+                       head_length=arrowHeight, head_width=arrowWidth,
+                       length_includes_head=True)


Test patch:
diff --git a/raytracing/tests/testsLaserPath.py b/raytracing/tests/testsLaserPath.py
new file mode 100644
index 0000000..6b90b03
--- /dev/null
+++ b/raytracing/tests/testsLaserPath.py
@@ -0,0 +1,26 @@
+import unittest
+import envtest  # modifies path
+from raytracing import *
+
+inf = float("+inf")
+
+
+class TestLaserPath(unittest.TestCase):
+
+    def testEigenModes(self):
+        lp = LaserPath([Space(10)])
+        self.assertTupleEqual(lp.eigenModes(), (None, None))
+
+        lp = LaserPath()
+        self.assertTupleEqual(lp.eigenModes(), (None, None))
+
+        lp = LaserPath([CurvedMirror(-10)])
+        self.assertNotEqual(lp.eigenModes(), (None, None))
+
+    def testLaserModes(self):
+        lp = LaserPath()
+        self.assertListEqual(lp.laserModes(), [])
+
+
+if __name__ == '__main__':
+    unittest.main()