Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

General polarization ray tracing #112

Open
kalosu opened this issue Dec 18, 2024 · 6 comments
Open

General polarization ray tracing #112

kalosu opened this issue Dec 18, 2024 · 6 comments

Comments

@kalosu
Copy link

kalosu commented Dec 18, 2024

Hello there community from poke,

First at all, thanks a lot for putting this nice tool available for everyone.

I would like to know if what I want to do is supported at the moment by your tool.

I have some electric field components (Ex, Ey and Ez) which I extracted from a FDTD simulation. With this, I am able to generate a ray bundle, i.e, a set of rays which are perpendicular to the common wavefront to these field components.

Using this I have performend non sequential ray tracing using Zemax but in this case, the rays just carry the "intensity" obtained from the Poynting vector.

I would like to extend this to the case in where I trace the field components along the ray directions and consequently calculate the transmitted field components through a non sequential optical system.

At the end, I want to have a detector and I want to be able to "observe" each individual field component traced through the system.

Would this be something that I could consider doing with poke? Do you have any reference on how to define a general ray set source?

Since I am doing a non sequential ray tracing, this would mean that I need to set the amplitude and phase for all components associated to each ray right? Any idea on how could this be performed?

Thanks for the comments!!

@Jashcraf
Copy link
Owner

Hi there and thanks for considering Poke 😀

If you can represent the output of your FDTD into a vector in the global coordinates of your optical system (array of [x, y. z]) or the local coordinates of the system's entrance pupil (array of [x, y]) then you can propagate it via polarization ray tracing, which Poke does support!

What Poke does not currently support is a way to load data from Nonsequential ray traces. This isn't a hard limit, I just haven't gotten around to implementing it yet.

If you would like to work on a PR to get non-sequential ray tracing working for Poke, I'd be happy to send you some resources to get started!

@kalosu
Copy link
Author

kalosu commented Dec 18, 2024 via email

@Jashcraf
Copy link
Owner

Yes, from my FDTD simulation I basically obtain the far-field components
Ex, Ey and Ez which I guess I can directly use to set the polarisation
associated to each ray?

We should take a look at the details, but in principle if you have the far-field components you can use it (or its Fourier transform) as the input to a polarization ray trace simulation. The effect is essentially setting the polarization of each ray, but there are some computational tricks that might help if your input signal has high-frequency components.

As for the non sequential ray tracing, what do you mean that currently it
does not support loading data from non sequential ray tracers? Are the ray
tracing calculations performed using sequential ray tracing?

Poke operates by the following principle:

    1. Use ray tracer (OpticStudio/CODE V) Python API to do ray tracing (poke.raytrace)
    1. Save ray data to a poke.Rayfront object
    1. Perform the 3D polarization ray tracing calculus using poke.polarization

Step 1. requires the writing of an interface with a given ray tracer's Python API. For example, we currently support OpticStudio's sequential ray tracing mode:

def trace_through_zos(raysets, pth, surflist, nrays, wave, global_coords):

Unfortunately, the interface between OpticStudio's sequential and non-sequential ray tracing modes are different - so we would need a trace_through_zos_nonsequential function to support non-sequential ray traces. However, I have an example file from the Zemax knowledgebase that has everything you need to do pretty rapid non-sequential ray tracing via the OpticStudio Python API.

Btw, I just have access to OpticStudio. I am aware that polarisation ray
tracing works in the sequential mode there but I did not find any relevant
information on the non sequential case. Do you maybe know something about
this?

My experience with OpticStudio is that the single polarization ray trace in sequential mode tends to work, but the other analysis functions (e.g. polarization pupil map) tend to experience erroneous phase wrapping for some reason. One of the reasons I wrote Poke was to make an open-source platform for these kinds of simulations so that I could work with the community on figuring out the origin of some of these discrepancies. And now it's been validated against both OpticStudio + CODE V's sequential ray tracing modes to (near) machine precision.

Here's one of the sample files from Michael Humphreys, whose Raytrace.dll has saved me hours of simulation time.
https://github.com/Jashcraf/Polarization-Raytrace/blob/df53bad3047c59fd562b0cb49a2361497f1d37ab/ZOS-API-samples/PythonNET_ZRDLoaderFull.py#L129

You just need to create a function that loads in the non-sequential file you want to simulate, and then get all of the ray data from the resulting "results" object.

https://github.com/Jashcraf/Polarization-Raytrace/blob/df53bad3047c59fd562b0cb49a2361497f1d37ab/ZOS-API-samples/PythonNET_ZRDLoaderFull.py#L174

There may be some debugging required if OpticStudio's "results" is different between non-sequential and sequential. But that's the gist of what needs to get added before you can use Poke to do PRT on non-sequential files. I would note that this is a pretty substantial addition in terms of expanding Poke's capabilities, so I'd be happy to add you as a co-author to the next conference proceedings I publish for Poke if you have the time to make a PR :D.

@kalosu
Copy link
Author

kalosu commented Jan 3, 2025

Hi @Jashcraf,

Thanks for the nice feedback and provided details. I have to say that my experience and knowledge about polarization ray-tracing is basically none 😅

After your feedback, I took some time to read a bit through the book "Polarized Light and Optical Systems" to get a basic idea about what is going on.

From this, I decided to first try the available sequential ray tracing based interface to get an initial working example in my system.

For this case, I would like to have a plot in where I can observe the polarization state of my incident wavefront. I guess for this I would need to plot the polarization ellipses right? Would this be something supported by Poke at the moment? Or do you have any suggestion on how can I visualize the polarization vectors of my incident wavefront?

I was following the book guidelines to determine if the light is linearly polarized or not across my wavefront from where I noticed that the 0 or 180 degrees phase difference condition is not satisfied for all points on my wavefront surface. However, I would prefer to have a different and more "intuitive" way of visualizing the polarization state of my incident field in this case.

Maybe you have some comments about this? Do you have any suggestion on how could I obtain such a plot with Poke?

@Jashcraf
Copy link
Owner

Jashcraf commented Jan 8, 2025

At the moment I don't have a built-in function for plotting polarization ellipses across the pupil. To make such a plot, you need the eigenvectors of the jones pupil (which you can get with np.linalg.eig). You then pick the "fast" polarization state, and use the eigenvector to compute the polarization ellipse (https://en.wikipedia.org/wiki/Elliptical_polarization#Polarization_ellipse). You can plot the ellipses using matplotlib's "Patches"

@kalosu
Copy link
Author

kalosu commented Jan 9, 2025

Hello again @Jashcraf,

I have managed to implement an initial interface for the non-sequential case. Just to give you a brief idea about what I did:
-I implemented the non-sequential ray-tracing routine which is slightly different from the sequential case.
-The returned data from the non-sequential call is also a bit different. One important thing is that no surface normals information is returned. Therefore, I had tocalculate these from the incident and output ray directions for each ray, at each interface. (Differently from the sequential case, it seems that it is not possible to just take the rays associated to a single surface. Instead, you have to go ray by ray and extract the ray segments which are traced through the system).
-Another key point here is that in the non-sequential case, the concept of pupil coordinates and field points is not used. Instead, each ray bundle needs to be defined using the initial ray coordinates and the direction cosines directly.
-Once the tracing is completed and the kin, kout, normals and aoi are calculated, then I use the same functions that you had already provided within Poke to do the polarization ray-tracing calculations.

When I compare the sequential and non-sequential case results, the agreement is somehow good. However, the results are not exactly the same. First, we can compare the output field components generated for a linearly polarized point source. (I obtained the output field components by multiplying the input field by the P t o t a l matrices)
sequential_non_sequential

So here you can see that the results are close but are not exactly the same, specially for the magnitude of the E z component. Notice that my system produces a collimated output, meaning that E z should be 0 in this case.

If I compare the total irradiance for both cases, then we can see:

irradiances_sequential_non_seq_comparison

In this case, the non-sequential case has a central region irradiance that has a wider in contrast to the sequential case.

Finally we have the Jones pupils. Here I was not really sure if this makes sense since again, there are no pupil coordinates for the non-sequential case. (Upper figure corresponds to the non-sequential case)

jones_pupil_seq_non_seq

In this case, the differences are clearer. So far, it looks that it is kind of working. However, I am not sure about the cause for the differences between the sequential and non-sequential case. Both systems are the same, the only thing is that for the non-sequential case, I used a STEP file for my first lens. However, I would not expect this to be the main reason here.

One thing that I noticed is that all direction cosines are expressed in the global coordinate system basis for the non-sequential ray-tracing case. There is no need to perform a basis transformation. However, the results returned by the sequential ray-tracing case are expressed in terms of the local basis (I assume that this means the basis for which the local z is aligned with the surface normal) and I could not find a way to express these in the global basis since the transformation matrix returned by Zemax for each surface is just an identity matrix. I am not sure if this could also have an effect. What do you think? Should this matter?

Do you maybe have some ideas on what could be happening here? Or maybe you have some suggestion on what should I check for to validate the results? Any recommendation?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants