mjhoptics / ray-optics

geometric ray tracing for optical systems
BSD 3-Clause "New" or "Revised" License
271 stars 58 forks source link

How to set decenter/tilt in a correct way #153

Open TLawu opened 2 months ago

TLawu commented 2 months ago

Dear Mike,

I raised an issued in mjhoptics/ray-optics-notebook. Since it didn't have other issues, then I put the link here. https://github.com/mjhoptics/ray-optics-notebooks/issues/16

Hopefully, I can get the solution. Best regards, Tjundewo

mjhoptics commented 2 months ago

Hi @TLawu,

First, I think the layout plot is misleading, if not wrong. So this is an issue. I'll look into this.

Second, I presume your intent is to "float" the 2nd lens inside of the immersing medium. In this case, the entries for the second, reverse decenter need to be modified a bit.

The reverse decenter is the correct choice for returning to the original axis. The angles are applied in reverse, making entry for this case simple.

The translation, however needs adjustment. The translation between surfaces 4 and 5 is tilted by a 5 deg angle, so the distance along the original Z axis is cos(tilt)lens_thickness. The change in the original thickness can be input as a Z-component of the decenter. The vertex of the 2nd lens surface, surface 5, is further from the axis than surface 4. The y decenter for surface 5 should be original_offset+sin(tilt)lens_thickness. The inputs, suitably parameterized, look like this:

sm.ifcs[4].decenter = srf.DecenterData('decenter')
sm.ifcs[5].decenter = srf.DecenterData('reverse')

offset=0.5
tilt=5.0
tilt_rad=np.deg2rad(tilt)
thi=sm.gaps[4].thi
sm.ifcs[4].decenter.dec = np.array([0., offset, 0.])
sm.ifcs[5].decenter.dec = np.array([0., 
                                    offset + np.sin(tilt_rad)*thi, # y decenter
                                    (np.cos(tilt_rad) - 1)*thi])   # z decenter
sm.ifcs[4].decenter.euler = np.array([tilt, 0., 0.])
sm.ifcs[5].decenter.euler = np.array([tilt, 0., 0.])
opm.update_model()

There is a method in seq_model to print all of the surface coordinates in a single, global, coordinate system. The format for each surface is the rotation matrix, following by the vertex coordinate vector.

sm.list_gbl_tfrms()
 0:    1.000000    0.000000    0.000000       0.00000
       0.000000    1.000000    0.000000       0.00000
       0.000000    0.000000    1.000000  -10000000000.00000

 1:    1.000000    0.000000    0.000000       0.00000
       0.000000    1.000000    0.000000       0.00000
       0.000000    0.000000    1.000000       0.00000

 2:    1.000000    0.000000    0.000000       0.00000
       0.000000    1.000000    0.000000       0.00000
       0.000000    0.000000    1.000000       0.55000

 3:    1.000000    0.000000    0.000000       0.00000
       0.000000    1.000000    0.000000       0.00000
       0.000000    0.000000    1.000000       3.60000

 4:    1.000000    0.000000    0.000000       0.00000
       0.000000    0.996195    0.087156       0.50000
       0.000000   -0.087156    0.996195       3.60000

 5:    1.000000    0.000000    0.000000       0.00000
       0.000000    0.996195    0.087156       0.84862
       0.000000   -0.087156    0.996195       7.58478

 6:    1.000000    0.000000    0.000000       0.00000
       0.000000    1.000000    0.000000      -0.00000
       0.000000    0.000000    1.000000      24.19655

It is also useful to use listobj() to get at all the data for an object.

listobj(sm.ifcs[5])
transmit
profile: Spherical
c=-0.16666666666666666,   r=-6.0
decenter type: reverse
decenter: [ 0.          0.84862297 -0.01522121]
euler angles: [5. 0. 0.]
surface_od=3.0

I believe the raytrace results for the decentered model are correct, but the layout clearly isn't useful as it stands. I'll look into it. Mike

TLawu commented 2 months ago

Dear Mike,

Thanks for the quick response. So, in this case, I need to handle surface 5 for return dec and the problem is in the layout, but not the ray trace.

When I need to shift and tilt the pupil, is it better to shift and tilt all other components (not the STOP itself)? Currently, I use Zemax and want to stop using it in the future. My needs are only to calculate the optical model (eye model) in this issue (and its little modification) with dec/tilt in pupil, lens and/or cornea. Analyses are only paraxial focus, LSA, and wavefront error. These analyses are done based on your valuable advices previously (in the discussion about constant index) I can calculate the PSF, MTF using the resulted wavefront error.

Regards, Tjundewo

mjhoptics commented 2 months ago

Tjundewo, You should be able to decenter the stop surface directly without having to modify the rest of the model. Mike

TLawu commented 2 months ago

Dear Mike,

Just to confirm, to decenter the stop surface, are decenter and reverse at the same surface number?

sm.ifcs[3].decenter = srf.DecenterData('decenter')
sm.ifcs[3].decenter = srf.DecenterData('reverse')

sm.ifcs[3].decenter.dec = np.array([0., 0.5, 0.])
sm.ifcs[3].decenter.dec = np.array([0., 0.5, 0.])

Thank you. Tjundewo

mjhoptics commented 2 months ago

For this situation, the 'dec and return' decenter type is the best choice.

sm.ifcs[3].decenter = srf.DecenterData('dec and return')
sm.ifcs[3].decenter.dec = np.array([0., 0.5, 0.])

This decenter type decenters and tilts the surface and then returns to the starting point and orientation.

TLawu commented 2 months ago

Dear Mike,

Great. This 'dec and return' solve my doubt for decentering/tilting for one surface. I assume 'dec and return' applied also for tilt

sm.ifcs[3].decenter = srf.DecenterData('dec and return')
sm.ifcs[3].decenter.dec = np.array([0., 0.5, 0.])
sm.ifcs[3].decenter.euler = np.array([5., 0., 0.])

and since only one surface, then no need to calculate offset as explained above.

I do hope also for the improvement of the layout.

Additionally, I can set pupil float by stop using set_pupil(opm) and set entrance pupil diameter by osp['pupil'].value. When using set_pupil(opm), then the sd value of stop is applied to trace the correct osp['pupil'].value But when using osp['pupil'].value, the sd value of stop is remain unchanged. How to set the correct sd value to the surface stop based on the trace result osp['pupil'].value? I need to do this when calculating the wavefront to get the correct size.

wfe = rayoptics.raytr.analyses.eval_wavefront(opm, fld, wvl, foc, num_rays=65)

Best regards,

Tjundewo

mjhoptics commented 2 months ago

Yes, this works if the surface is tilted also.  MikeOn Aug 19, 2024, at 11:44 PM, TLawu @.***> wrote: Dear Mike, Great. This 'dec and return' solve my doubt for decentering/tilting for one surface. I assume 'dec and return' applied also for tilt sm.ifcs[3].decenter = srf.DecenterData('dec and return') sm.ifcs[3].decenter.dec = np.array([0., 0.5, 0.]) sm.ifcs[3].decenter.euler = np.array([5., 0., 0.]) and since only one surface, then no need to calculate offset as explained above. I do hope also for the improvement of the layout. Best regards, Tjundewo

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you commented.Message ID: @.***>