quartiq / rayopt

Python optics and lens design, raytracing
GNU Lesser General Public License v3.0
254 stars 50 forks source link

GaussianTrace fails on "folded" systems #18

Closed mwiebold closed 7 years ago

mwiebold commented 7 years ago

Trying to do a GaussianTrace on a system with folding mirrors. It will work if I don't fold the system, but the GaussianTrace plotting fails when I have the fold mirrors in the prescription.

It looks like elements' rot_axis isn't being set in some cases. If the element is straight but not normal, rot_axis won't be set, but is used in the from_axis method, which is used at least in GaussianTrace.

The below returns

AttributeError: 'Spheroid' object has no attribute 'rot_axis'

MWE:

import rayopt as ro
import matplotlib.pyplot as plt
import numpy as np

plt.close('all')

src = ro.Spheroid(material = ro.vacuum,
                  radius = 10.0e-3,
                  distance = 0.0)

m1 = ro.Spheroid(material = ro.mirror,
                 radius = 20.0e-3,
                 offset = (0.0, 0.0, 0.1),
                 angles = (-np.pi/4.0, 0.0, 0.0))

m2 = ro.Spheroid(material = ro.mirror,
                 radius = 20.0e-3,
                 offset = (0.0, 0.1, 0.0),
                 angles = (np.pi/4.0, 0.0, 0.0))

det = ro.Spheroid(material = ro.vacuum,
                  radius = 10.0e-3,
                  offset = (0.0, 0.0, 0.1),
                  angles = (0.0, 0.0, 0.0))

optics = ro.System(wavelengths = [355.0e-9],
                   scale = 1e0)

optics.extend([src, m1, m2, det])

optics.object = ro.FiniteConjugate(radius = 3.0e-3,
                                   pupil = dict(type = 'na',
                                                na = 0.1))

optics.update()

fig, ax = plt.subplots()
optics.plot(ax)

#for idx, el in enumerate(optics):
#    print('Element {}:'.format(idx))
#    print('  rotated:  {}'.format(el.rotated))
#    print('  straight: {}'.format(el.straight))
#    print('  normal:   {}'.format(el.normal))
#    print('  _distance:   {}'.format(el._distance))
#    print('  _direction:   {}'.format(el._direction))
#    print('  _offset:   {}'.format(el._offset))
#    print('  _angles:   {}'.format(el._angles))
#    print('  rot_axis:   {}'.format(el.rot_axis))

# Straight is if the direction is (0,0,1)
# Normal is if angles are all zero
# Rotated is if it is either not straight or not normal

gt = ro.GaussianTrace(optics)

fig, ax = plt.subplots()
gt.plot(ax)
optics.plot(ax)

image

jordens commented 7 years ago

As a workaround, you can just drop all the angles= and then use optics.align(n=[1. for el in optics]) (after update()) to have them computed for you. As a sidenote mapping the geometric ray trace terminology to the Gaussian trace is not sometimes ambiguous. With a finite object rayopt will use the object position and size for waist position and waist size. With an infinite object it will use the pupil size and position for waist. That should be extended to a different behavior with NAPupil, but the analogy gets tricky...