Skip to main content

Simulate 2D diffraction grating using customized diffractive DLL


Michael Cheng
Zemax Staff
Forum|alt.badge.img+2

In OpticStudio, currently we only support one dimensional grating. However, it's not difficult to simulate 2D grating. Here we will show an example using diffractive DLL.

You may compile it with the instructions or use the DLL file attached to this article. 

Before we start, here are some articles for required background knowledge that we will not repeat in this forum post.

  1. How diffractive surfaces are modeled in OpticStudio (KBA)

  2. How diffraction ray-tracing is calculated | Zemax Community(forum post)

  3. Custom DLLs in OpticStudio: An overview of user-defined surfaces, objects, and other DLL types (KBA)

  4. How to compile a User-Defined DLL (KBA)

Let's simply open the attached cpp file and observe how it works in non-sequential mode.

This example is mainly modified from the built-in sample \Documents\Zemax\DLL\Diffractive\diff_samp_1.c 

To compile the program as C++ code. We package the functions with extern 'C'.

 

200611-121820-image.png

 

In this example, we only want to return diffraction ray direction and its relative intensity. So setting data[31] = 1 is enough. If we also know the polarization state or the full eletric field value, we can use data[31] = 2.

 

200611-121919-image.png

 

Here assumes we want to simulate 5 orders in x and y direction, so there should be totally 25 orders from (-5,-5) to (5,5). Because currently OpticStudio only considers the diffractive DLL simulates 1D grating, we need to represent the 2D orders in 1D. Here we will only consider orders from 0 to 24, which represents (-2,-2) to (2,2). If OpticStudio requests orders other than this range, we return -1, which will result in an geometric error in OpticStudio. For this reason, when using this DLL, the Start Order should be 0 and Stop Order should be 24 in OpticStudio.

 

200611-122135-image.png

 

200611-122849-image.png

 

Then, we can decompose the 1D order into corresponding 2D orders.

 

200611-132541-image.png

 

When data[31] = 1, we need to return the value for phase derivative and phase accumulation.  

 

200611-141248-image.png

200611-132810-image.png

 

Note the phase derivative is same as what we described in page 3 in this forum post: How diffraction ray-tracing is calculated | Zemax Community

The phase (variable 'P') is simply accumulation of the phase assuming the phase at surfase vertex is zero.

 

200611-140955-image.png

 

In UserParamNames(), we define the efficiency for each diffraction order.

 

200611-141411-2020-06-11_14-13-23.jpg

 

Then simply read it to data[30], which is the relative intensity reported to OpticStudio!

 

200611-141623-image.png

Did this topic help you find an answer to your question?

17 replies

Michael Cheng
Zemax Staff
Forum|alt.badge.img+2
  • Author
  • Zemax Staff
  • 137 replies
  • July 22, 2020

Attached is a example for user defined surface used in sequential mode. This is modified from the built-in us_grate.c. The concept is same as above, but with one main difference: there need to be two parameters Order X and Order Y to let users explicitly specify what order to trace. This is because in sequential mode, only one path can be traced at once.


Only two parts are changed.


1. Add two parameters for x directional periodicity.



2. Code added to consider for another periodicity in x direction.

T,M becomes Tx,Ty,Mx,My.

Adding code for dpdx. Just mimics dpdy and that's it!



Mark.Nicholson
Luminary
Forum|alt.badge.img+3

Gotta say Michael, you are doing some seriously good work here. Well done!


Michael Cheng
Zemax Staff
Forum|alt.badge.img+2
  • Author
  • Zemax Staff
  • 137 replies
  • July 23, 2020

Hey Mark, that's great to see your reply and I'm glad you like it!


  • Monochrome
  • 4 replies
  • June 9, 2023
Michael Cheng wrote:

In OpticStudio, currently we only support one dimensional grating. However, it's not difficult to simulate 2D grating. Here we will show an example using diffractive DLL.

You may compile it with the instructions or use the DLL file attached to this article. 

Before we start, here are some articles for required background knowledge that we will not repeat in this forum post.

  1. How diffractive surfaces are modeled in OpticStudio (KBA)

  2. How diffraction ray-tracing is calculated (forum post)

  3. Custom DLLs in OpticStudio: An overview of user-defined surfaces, objects, and other DLL types (KBA)

  4. How to compile a User-Defined DLL (KBA)

Let's simply open the attached cpp file and observe how it works.

This example is mainly modified from the built-in sample \Documents\Zemax\DLL\Diffractive\diff_samp_1.c 

To compile the program as C++ code. We package the functions with extern 'C'.

 

200611-121820-image.png

 

In this example, we only want to return diffraction ray direction and its relative intensity. So setting data[31] = 1 is enough. If we also know the polarization state or the full eletric field value, we can use data[31] = 2.

 

200611-121919-image.png

 

Here assumes we want to simulate 5 orders in x and y direction, so there should be totally 25 orders from (-5,-5) to (5,5). Because currently OpticStudio only considers the diffractive DLL simulates 1D grating, we need to represent the 2D orders in 1D. Here we will only consider orders from 0 to 24, which represents (-5,-5) to (5,5). If OpticStudio requests orders other than this range, we return -1, which will result in an geometric error in OpticStudio. For this reason, when using this DLL, the Start Order should be 0 and Stop Order should be 24 in OpticStudio.

 

200611-122135-image.png

 

200611-122849-image.png

 

Then, we can decompose the 1D order into corresponding 2D orders.

 

200611-132541-image.png

 

When data[31] = 1, we need to return the value for phase derivative and phase accumulation.  

 

200611-141248-image.png

200611-132810-image.png

 

Note the phase derivative is same as what we described in page 3 in this forum post: How diffraction ray-tracing is calculated.

The phase (variable 'P') is simply accumulation of the phase assuming the phase at surfase vertex is zero.

 

200611-140955-image.png

 

In UserParamNames(), we define the efficiency for each diffraction order.

 

200611-141411-2020-06-11_14-13-23.jpg

 

Then simply read it to data[30], which is the relative intensity reported to OpticStudio!

 

200611-141623-image.png

Hi,Michael!

      I meet a problem that when setting  data[31] = 2 in the built-in sample \Documents\Zemax\DLL\Diffractive\diff_samp_1.c and output the new DLL ,  Diffraction Grating with the new DLL in which data[31] = 2 can not receive beam rays, namely the light beams can not reach the diffraction grating.

Why it become like this?

 

      Looking forward to your reply! Thank you !

 

zhouqing

 


Michael Cheng
Zemax Staff
Forum|alt.badge.img+2
  • Author
  • Zemax Staff
  • 137 replies
  • June 10, 2023

Hi Zhouqing,

Thank you for reply. Setting data[31] = 2 should be not a problem. The problem probably happens at your other code. Could you send your question to support inbox so we can help to further look at your question? Thank you!

Michael

 

 

 


  • Monochrome
  • 4 replies
  • June 10, 2023
Hi Michael!  Thank you very much for your reply!
 
   I have send my question to the mailbox Zemax Community <community@zemax.com>. In case of encountering problems when sending the email,I also present my questions in more detail as below:
           Firstly, I just change the code data[31] = 1 to data[31] = 2  in the built-in sample \Documents\Zemax\DLL\Diffractive\diff_samp_1.c and output the new DLL.
           When I use the new DLL in Diffraction Grating in NSC mode, the light beam can not reach the grating. Maybe there are something wrong when I changed the code in the built-in sample \Documents\Zemax\DLL\Diffractive\diff_samp_1.c.
 
           Then I review the DLL in ZEMAX Knowledgebase(KBA), there are some keys as shown below:
             s?func=mbox:getMessageData&sid=g0bAX7p2j080qEP6D49TO35KFnAAqwQk&mid=AEgAlwBsJLADUX9G95avgqpG&Part=3
               s?func=mbox:getMessageData&sid=g0bAX7p2j080qEP6D49TO35KFnAAqwQk&mid=AEgAlwBsJLADUX9G95avgqpG&Part=4
           According to the above content, If I set the code data[31] = 2  , then the data[35]~[37], and data [40]~[45] should also be calculated or set. For the further code setting of  data[35]~[37] and data [40]~[45] , I still feel  a bit difficult to input the perfect new codes as I am not familiar with the C++ and ZEMAX Programming logic for Diffractive DLL.
 
            If Michael could give me some help or suggestions for the above tricky situation as I meet.
 
            Looking forward to your reply!   Thank you!
 
Zhouqing

 


Michael Cheng
Zemax Staff
Forum|alt.badge.img+2
  • Author
  • Zemax Staff
  • 137 replies
  • June 11, 2023

Hi Zhouqing,

I’m sorry for confusion, but could you try to create a case via the following link.

https://support.zemax.com/hc/requests/new

Or, you can also send the question to the support box: zemax.support@ansys.com

Both method will reach to the same team. Using the link is suggested as you will be able to check the status of the tickets. Please note you will need to create a Zemax account in order to open a ticket. Please let us know if you have any issue. Thank you.


  • Monochrome
  • 4 replies
  • June 11, 2023

Thank you, Michael!

 

I have send my question to the support box: zemax.support@ansys.com

 

At the same time, I also present my questions again as below:

 I just change the code data[31] = 1 to data[31] = 2  in the built-in sample \Documents\Zemax\DLL\Diffractive\diff_samp_1.c and output the new DLL.When I use the new DLL in Diffraction Grating in NSC mode, the light beam can not reach the grating. Maybe there are something wrong when I changed the code in the built-in sample \Documents\Zemax\DLL\Diffractive\diff_samp_1.c. 

 

  Then I review ” Custom DLLs in OpticStudio: An overview of user-defined surfaces, objects, and other DLL types”in ZEMAX knowledgebase (KBA), there are some keys as shown below:

     “ If data[31] equals 2, it must also calculate data 35-45, the complete output ray data. The DLL should return 0 if successful, and -1 if it encountered an error. For a complete description of all the data items passed between ZOS and the Diffraction DLL, please see the example {Zemax}\DLL\Diffraction\diff_samp_1.c.

     Note when the data[31] is 2, the power of diffracted ray is mainly calculated by the returned field data in data[40-45]. However, the data[30] can still affect the ray-tracing in two ways. One is that OpticStudio will use data[30] for estimating the Lost Energy, which shows in the Ray Trace dialog, during raytracing. One is that the diffractive ray will stop tracing if the value in data[30] is smaller than Minimum Relative Ray Intensity in the System Explorer.

           According to the above content,  If I set the code data[31] = 2  , then the data[35]~[37], and data [40]~[45] in the built-in sample diff_samp_1.c should also be calculated. For the further code setting of  data[35]~[37] and data [40]~[45] , I still  feel  a bit difficult to write the perfect new codes as I am not familiar with the C++ and ZEMAX Programming logic for Diffractive DLL.

            If Michael could give me some help or suggestions for the above tricky situation as I present.

            Looking forward to your reply!   Thank you!

 

Zhouqing


Calogero
  • Single Emitter
  • 1 reply
  • January 16, 2024

Thanks for the tutorial Michael, very informative.

 

I have tried to implement a similar code that the one you provide here but to also analize the reflection modes of a simple 2D grating. In my case I restricted the Tranmission and Reflection modes to (-1,-1) → (1,1). 

 

In my case the call for input parameters looks like this:

 

 

I have tried to modify data[11] value to accomodate either tranmission and reflection modes asking which mode is being calculated as follows:

 

 

but this proven not to work. Zemax only calculated the transmissive modes and all the reflection modes are there but as simple reflection from a glass surface.

 

 

Could you please give me a hint on how to implement this properly?

 

Thank you!


Yuqiang.Ding
  • Single Emitter
  • 4 replies
  • July 20, 2024

Hi, Michael.

Thanks for your input to the community. I am wondering how the zemax calculate the power of ray, which comes out of the DLL surface (RCWA model for a grating). In the DLL, data [30] represents relative energy of the ray. Here I assum it is diffraction efficiency, which is power flow. Besides, the output electric is also required to give in data [40-45]. Based on my test, the zemax detector seems to calculate the energy of the ray from DLL based on its square module of electric field instead of diffraction efficiency. However, when the diffraction efficiency of first order of light is high, e.g. 99.9%. The square module of electric field is usually larger than 1 because the k-vector changes. Therefore, I have normalize the electric field and multiple square root of the diffraction efficiency to achieve the right number on detector, which is contradictory to the law of wave propagation. Besides, If I did this, the detector energy will change again when this ray from DLL interact with next surface, which is a glass usrface with perfect AR coating. . Do you know what is happening? 

Here is my setup. The power on detectors inside glass is 99.941%, which is exactly same as the diffraction efficiency. The power on detector outside of glass is 99.864%. I also tested the AR coating. It is perfect for different incident angles and impossible to influence such 0.1% power variation.

 


Michael Cheng
Zemax Staff
Forum|alt.badge.img+2
  • Author
  • Zemax Staff
  • 137 replies
  • July 22, 2024

Hi Yuqiang,

I feel there are some specific problem in your code and the test. It’s probably best you send your question through support so we can look into details to know the exact issue. However, I guess the following principles can be useful.

  1. It’s correct OpticStudio uses [40-45] for the power of the ray not data[30], when data[31] is 2. However, you should still make sure data[30] = sum(data[40]^2+data[41]^2+...data[45]^2)_output / sum(data[40]^2+data[41]^2+...data[45]^2)_input.
  2. sum(data[40]^2+data[41]^2+...data[45]^2)_input >= sum(data[40]^2+data[41]^2+...data[45]^2)_output
  3. The electric field should be perpendicular to ray direction. Namely, when you return data, you should make sure data[4]*data[40]+data[5]*data[42]+data[6]*data[44]=0 and data[4]*data[41]+data[5]*data[43]+data[6]*data[45]=0

Hope these are useful information.


Yuqiang.Ding
  • Single Emitter
  • 4 replies
  • July 23, 2024
Michael Cheng wrote:

Hi Yuqiang,

I feel there are some specific problem in your code and the test. It’s probably best you send your question through support so we can look into details to know the exact issue. However, I guess the following principles can be useful.

  1. It’s correct OpticStudio uses [40-45] for the power of the ray not data[30], when data[31] is 2. However, you should still make sure data[30] = sum(data[40]^2+data[41]^2+...data[45]^2)_output / sum(data[40]^2+data[41]^2+...data[45]^2)_input.
  2. sum(data[40]^2+data[41]^2+...data[45]^2)_input >= sum(data[40]^2+data[41]^2+...data[45]^2)_output
  3. The electric field should be perpendicular to ray direction. Namely, when you return data, you should make sure data[4]*data[40]+data[5]*data[42]+data[6]*data[44]=0 and data[4]*data[41]+data[5]*data[43]+data[6]*data[45]=0

Hope these are useful information.

 

Thanks, Michael.

I will check one by one. Could you share how zemax calculate the energy of ray at different scenarios? It looks like zemax will use relative energy in some situations, but use inner product in other situations.

 

Best,

Yuqiang


Michael Cheng
Zemax Staff
Forum|alt.badge.img+2
  • Author
  • Zemax Staff
  • 137 replies
  • July 24, 2024

Hi Yuqiang,

Do you mean data[30] by relative energy? As discussed above, when data[31] is 2, it’s not used as ray power, but it will be used for judging whether a ray should stop trace because of too low level of power. You can check the following article.

Custom DLLs in OpticStudio: An overview of user-defined surfaces, objects, and other DLL types – Knowledgebase (zemax.com)

Otherwise, I think it works as you expect where it changes the ray power.


Yuqiang.Ding
  • Single Emitter
  • 4 replies
  • September 19, 2024
Michael Cheng wrote:

Hi Yuqiang,

Do you mean data[30] by relative energy? As discussed above, when data[31] is 2, it’s not used as ray power, but it will be used for judging whether a ray should stop trace because of too low level of power. You can check the following article.

Custom DLLs in OpticStudio: An overview of user-defined surfaces, objects, and other DLL types – Knowledgebase (zemax.com)

Otherwise, I think it works as you expect where it changes the ray power.

Thank you for your insights, Michael.

I’m currently working on speeding up the DLL computation for diffractive optical elements. As we know, the RCWA model calculates the electric field and efficiency for each diffraction order (both transmission and reflection) in a single call. However, the current DLL template can only extract one order per call, requiring multiple redundant calls to retrieve, for example, the ±1 and 0 orders. This results in significant slowdowns—at least 6 times slower—due to repetitive calculations.

While this inefficiency is manageable for volume gratings (intensity or polarization type), which typically need only 3–5 harmonics for accurate RCWA results, surface relief gratings (SRG) often require over 50 harmonics. Repeating the process for each order wastes considerable computational resources, especially during optimization.

Do you have any suggestions for modifying the DLL to output multiple diffraction orders in a single call, thereby reducing computational waste?


Michael Cheng
Zemax Staff
Forum|alt.badge.img+2
  • Author
  • Zemax Staff
  • 137 replies
  • September 22, 2024

Hi Yuqiang,

Unfortunately, currently the interface will always call the DLL for each of harmonic orders. However, I think it’s usually not a major problem. If you have many orders to return, I think we should not really send out rays for all orders. If you do so, it means one ray is split into, for example, 50 rays. If 10 of these rays go back to the grating, they are further split into 500 rays. You will soon reach the limitation of segments and the simulation gets very slow. My suggestion would be you only set one diffraction order by using Start/Stop X/Y = 0, and in the DLL you will randomize the output based on output ray power. These are quite complicated programming task. If you have difficulty to do this, I would also suggest you describe what kind of application you want to do and see if we can consider this in the product feature. Thank you!


Yuqiang.Ding
  • Single Emitter
  • 4 replies
  • October 6, 2024
Michael Cheng wrote:

Hi Yuqiang,

Unfortunately, currently the interface will always call the DLL for each of harmonic orders. However, I think it’s usually not a major problem. If you have many orders to return, I think we should not really send out rays for all orders. If you do so, it means one ray is split into, for example, 50 rays. If 10 of these rays go back to the grating, they are further split into 500 rays. You will soon reach the limitation of segments and the simulation gets very slow. My suggestion would be you only set one diffraction order by using Start/Stop X/Y = 0, and in the DLL you will randomize the output based on output ray power. These are quite complicated programming task. If you have difficulty to do this, I would also suggest you describe what kind of application you want to do and see if we can consider this in the product feature. Thank you!

Dear Michael,

 

Thanks for your response. We are doing some waveguide displays with heavily interaction bettewen DLL (or BSDF file) and ray tracing. DLL-based BSDF could also accelerate the simulation speed. Could you give me some info (or an example) for building our own DLL-based BSDF?

 

Best,

Yuqiang


Michael Cheng
Zemax Staff
Forum|alt.badge.img+2
  • Author
  • Zemax Staff
  • 137 replies
  • October 8, 2024

Hi Yuquiang,

I think this is probably a little more than a question for the community. If possible, could you share your question to either channel partner or support system via Zemax

 

Best regards,

Michael

 

 


Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings