Skip to content
Snippets Groups Projects
README.md 8.35 KiB
Newer Older
# Topology optimization of blazed gratings under conical incidence

File : ```README.md```\
Author : ©Simon Ans\
Last update : 18/03/2024\
To get a pdf file from this ```.md``` file, run in a shell terminal :

> ```pandoc README.md --pdf-engine=xelatex -o README.pdf```

## About this directory

---

This directory gathers all the code files necessary to compute the mesh-based topology optimization of a periodic grating. Each element of the Finite Element triangulation can have a different permittivity in order to get the best reflection efficiency possible on a particular order for a given wavelength range.

**This model is described in "Topology optimization of blazed gratings under conical incidence" (S. Ans, G. Demésy, and F. Zamkotsian) available at https://arxiv.org/abs/2403.10174.**

## Quick Start

---

#### **Software Requirements**

Make sure you have got all the following softwares and that they are updated :

* ```gmsh``` 4.11.1 and more (**The location is given in the header of ```config_topopt_conical_data.py```**),

* ```getdp``` 3.5.0 and more (**The location is given in the header of ```config_topopt_conical_data.py```**),

* ```python``` 3.10 and more, with the libraries ```numpy```, ```scipy```, ```matplotlib.pyplot```, ```joblib```, ```os```, ```multiprocessing```, ```time```, ```meshio``` and most importantly ```nlopt``` (https://github.com/stevengj/nlopt). The code has been written using a machine with ```Miniconda3``` installed, hence the ```python``` command is used instead of ```python3```.

#### **Launch the optimization**

While being in this directory, run in the shell terminal

> ```$ python topopt_conical_main.py```

The two main files of interest are ```rho_opt.pos``` and ```rho_opt.txt```. They define the optimal density distribution in two ways. The first one can be directly displayed with ```Gmsh``` and the second one is automatically displayed into the PDF file ```rho_opt.pdf```.

Once the plots and the results are analysed and/or moved, run

> ```$ sh topopt_conical_clean.sh```

## More detailed description of the directory

---

#### General organization

* ```config_topopt_conical_data.py``` : a Python file that gathers all the data for the simulation,

* ```topopt_conical_main.py``` : the main Python file that handles all the resolution and plots the results,

* ```resolution_functions.py``` : the Python file with all the functions that enable the resolution of the Finite Element problem and the plot of the results,

* ```optimization_functions.py``` : the Python file with the definition of the target and the computation of the Jacobian. There is also the test function for the adjoint method,

* ```tabs_material.py``` : a function that enables the main code to handle any material with its $\varepsilon_r$. See the website https://refractiveindex.info to add the materials,

* ```topopt_conical.geo``` : the geometrical description of the pattern and the definition of the mesh using ```Gmsh```,

* ```topopt_conical.pro``` : the computation file, that solves a given problem on the geometry defined by ```topopt_conical.geo``` with the Finite Element Method using GetDP,

* ```topopt_conical_clean.sh``` : a Shell script that cleans the directory after using.
  
#### **Parameters and results obtained**

The output is the local optimal density map ```rho_opt``` (depending on the initial density), saved in the files ```rho_opt.txt``` and ```rho_opt.pos```.

The main parameters are as follows - they are all defined in the ```config``` Python file :

| **Parameter**             | **Name in the scripts**    |  **Default value**   | **Description**|
|---------------------------|----------------------------|----------------------|----------------|
| $d$                       | ```period```               | 3300nm               | Period of the pattern |
| $h_{\text{PML}^+}$        | ```h_PML_sup```            | 500nm                | Superior PML height |
| $h_{\mathcal{S}^+}$       | ```h_super```              | 1500nm               | Superstrate height |
| $h_{\mathcal{S}^-}$       | ```h_subs```               | 200nm                | Substrate height |
| $h_{\text{PML}^-}$        | ```h_PML_inf```            | 200nm                | Inferior PML height |
| $h_d$                     | ```h_design```             | 650nm                | Height of the design region |
| $\Lambda_t$               | ```target_wavelength```    | [700nm]              | Target wavelengths for the optimization (Python list) |
| $A_e$                     | ```amplitude```            | 1                    | Amplitude of the incident electric field |
| $\theta_i$                | ```theta_i```              | 5°                   | Incidence angle on the (Oxy) plane |
| $\varphi_i$               | ```phi_i```                | -66°                 | Incidence angle on the (Oyz) plane |
| $\psi_i$                  | ```psi_i```                | 90°                  | Minimum polarization angle |
| $N$                       | ```nb_orders```            | 1                    | Number of diffraction orders computed in one direction (total is $[-N,N]$) |
|                           | ```wanted_order```         | -1                   | Order on which the optimization is proceeded |
|                           | ```material_superstrate``` | Air                  | Material for the superstrate |
|                           | ```material_min```         | Air                  | Material with minimal permittivity |
|                           | ```material_max```         | Fused silica         | Material with maximal permittivity  |
|                           | ```material_substrate```   | Silver (widerange)   | Material for the substrate |
|                           | ```num_threads_multilambda```| ```len(lambda_target)```                   | Number of threads to run the multi-wavelength optimization in parallel |
|                           | ```num_threads_resolution```| 1                   | Number of threads to run the Finite Element Method in parallel |
|                           | ```tol```                  | 1e-5                 | Tolerance of oscillation of the target function |
|                           | ```maxiter```              | 100                  | Maximum number of optimization iterations in a single binarization iteration |
|                           | ```filter_radius```        | 200nm                | Radius of diffusion for the connectedness |

#### Customization

##### **A flexible script**

There are other parameters in the ```config``` file, such as the initial configuration given in the ```analytic_init_density``` function (/!\ every length must be multiplied by ```nm```) and the refinement of the mesh with ```paramaille```, which is typically $\min(\Lambda_t)/h_{\max}$ ($h$ being the size of a mesh element). This size of the mesh can be defined differently in each region.

There are also several flags in order to decide if one wants binarization, connectedness, a metal, etc.

##### **Some other features**

During the optimization, the directory ```res_conical``` is created and filled with a lot of data. The most interesting are the efficiency files ```efficiency_*.txt``` on the targeted diffraction order. The current efficiency is always updated but there are also the ```efficiency_r_*_list.txt``` files that keep the evolutions of each diffraction efficiency in reflection.

Furthermore the total electric field is saved and updated. It can be directly displayed using ```Gmsh```. The adjoint fields are also available, although they are commented by default since they are not necessary for the optimization. The total absorption is also computed.

Finally, at each optimization step, an image of the current density distribution is saved with the name ```myimage_*.png```. It enables to directly make a film of the optimization process.

##### **Check the adjoint method**

In order to be sure that the adjoint method provides the same derivatives as the finite difference method (with the step ```h_0``` in the ```config``` file), there is the function ```optimization_functions.test_Target_n```. One can run some tests. In order to launch a run quickly, it is better to take a small period (max 100nm) on the order 0. However the pattern can be random.

The lines to launch this test is in the main function, and one can launch it by changing ```Flag_test``` to 1 in the ```config``` file. The relative difference between both Jacobians should be around $10^{-2}$ for a simple case.