Abstract
In this paper a novel Python library denominated POCAL is presented. POCAL (Python Optical Coating Analysis Library) allows to easily design optical coatings both as single layer and as multilayer stack, monitoring a wide variety of optical properties and, moreover, giving the possibility to automatically refine the multilayer design to achieve the desired optical goals. The library is completely open source, and it can be easily coupled to several Python-based ray tracers or libraries to work on more complex simulations. The results have been extensively tested and are comparable with the ones obtained using commercial software.
© 2023 Optica Publishing Group under the terms of the Optica Open Access Publishing Agreement
1. Introduction
The manufacturing of thin-film optical coatings is a challenging process: extremely thin layers with accurate thickness must be deposited on a substrate to obtain the desired optical properties. The production of thin-films optical filters has therefore always been assisted by ‘a priori’ calculations [1]. In the early days, multi-layer coating design was performed by graphical methods [2]. This procedure worked well for filters based on quarter-wave layers, but did not allow to design more elaborate configurations [3,4]. With the advent of computers, it has been possible to introduce new and more precise simulation tools, which allow the optimization of complex designs in a more accurate, more meticulous, and faster manner [5]. Additionally, switching to computer-based simulations gave scientists and engineers also the chance to combine coating design/analysis programs with other simulation software. This is required when designing optical systems that rely on multi-layer coatings for achieving their optical functionality [6]. One of the most relevant examples of simulation software that often incorporates the results of optical coating software is ray tracing programs. The popularity of ray tracing has been skyrocketing in the last three decades. This widely applicable approach to calculate the light propagation in a 2D or 3D system is exploited in various domains including the lighting, displays, automotive, energy, and gaming sectors [7–10]. To have a more precise and correct description of the simulated scenario, the optical properties of all the used materials must be known as detailed as possible. This is particularly true for optical coatings that are deposited on diverse materials to alter their standard optical properties. In fact, most of the mentioned fields take advantage of the unique properties of thin-film multilayer coatings to fine-tune the intensity or spectrum of the transmitted/reflected light [11,12]. Nowadays, both commercial and open-source software is available for the design and analysis of such optical coatings. Most of these programs are easy to use and allow to perform complex calculations in a very short timeframe [13]. However, one of the major drawbacks is represented by a lack of data uniformity between the coating design program output and the required input by the other software. If the input and output data formats are not of the same type, a time-consuming conversion is required, which can lead to errors. To solve this incompatibility issue, many laboratories and companies still use their own proprietary software. The main advantage of having internal software is the possibility of modifying the source code to the specific task that must be tackled. The Python programming language has been rapidly growing in popularity [14]: more and more people are using it for a wide variety of tasks that goes from data analysis and machine learning to graphic design and modeling [15–18]. Many research groups have also coded ray tracer libraries or packages to perform exact ray tracing in the Python framework [19,20]. Following this trend and intending to help other research groups and companies, we have developed a Python library to perform both coating analysis and design. The name of the library is POCAL, acronym for Python Optical Coating Analysis Library. The main advantage of having a Python package to perform accurate coating simulations is that it can be directly coupled or integrated with a Python-based ray tracer. Of course, the package can also be used as a standalone tool to perform fast and reliable analysis and design of multilayer coatings. POCAL starts from a simple two-column text file containing the prescription of the multilayer coating, which consists of the material type of each layer and its respective thickness (optical or physical). Once the coating prescription is defined, the package allows to calculate the optical transmission, reflection, and absorption of light at each wavelength, together with the phase shift of the reflected and transmitted light. Additional features are admittance diagrams, colorimetric analysis, and the calculation of the electric field inside the coating. No approximations have been used, to keep the results consistent and mathematically correct, while keeping the computational time limited. The full refractive index (real and complex part) of each of the available materials is listed in a .json file, which must be downloaded together with the library. This allows the users to check the refractive index of the materials, update them in case new data is available, and insert their own materials. In addition to the already mentioned features, the library has been enriched with an optimization tool that allows to set specific optical goals (e.g., one or more reflectance values at precise wavelengths) and, while performing several simulations, obtain the desired output by changing the thickness of the existing layers. At this moment, there already exist various software to perform thin-film coating analysis, ranging from online versions (e.g., Luxpop [21]), open-source codes (e.g., Openfilters [13], Freesnell [22], openTMM [23]), and commercial programs (e.g., Essential Macleod [24], OpTaliX [25]). Each of these programs has its own strengths: Luxpop does not require the installation of external programs, OpenFilters and Freesnell are free and allow various studies on the selected design, openTMM is a Python library, while Essential Macleod and OpTaliX are the commercial standards when speaking about thin-film design. Despite all these positive aspects, only a few of these tools are available in Python. Within the small circle of Python-based libraries that allow thin-film optical coating analysis, we have found that most of them are lacking some essential features, such as color analysis or a robust refinement process. Therefore, to satisfy the needs of the most demanding users, we have decided to code from scratch a Python library that allows to perform, without approximations, a thorough analysis of all relevant optical properties and, in addition, a feature to perform refinement of the thin-film multilayer stack to reach desired optical goals. The library is a completely free and customizable tool. It has been extensively tested and the results have been compared with the famous “Essential Macleod” design tool [24]. The paper is divided into several sections. In each section, we describe the physical formulae that are implemented to perform the various calculations and present the outputs considering a pre-defined example.
2. Method
2.1 How to download the library
The library can be downloaded from PyPI, the official software repository of the Python programming language. The installation is done using the pip command:
pip install pocal
To properly use the library, some supporting files are needed. They can be downloaded from GitHub at Ref. [26].
All the supporting files can be found in the resources folder available in the link above. The following commands can be used to make the resources folder the current working directory:
import os
os.chdir(path to resources folder)
If the resources folder path is, for instance, ‘C:\Users\Desktop\resources’, the command os.chdir(’C:\Users\Desktop\resources’) must be used.
The library can be called as follows:
import pocal
test = pocal.pocal(prescription, angle_in_deg, min_wave, max_wave, resolution, ref_wave, opt_thick, refinement_type)
Detailed and constantly updated installation steps and example scripts depicting the working of the library can be found on GitHub in Ref. [27]
The users using the POCAL library for research-related projects are kindly asked to cite this paper.
2.2 Coating design
The library requires a text file as input. This file describes the prescription of the considered thin-film stack. It must be written in a two-column-format, containing the chemical formula of the selected material in the first column, and the thickness (in nm – in the case of physical thickness – or as a fraction of the specific wavelength – in the case of optical thickness –) in the second column for each layer. The order of the layers is crucial to correctly design the stack: the surrounding (or immersing) medium (i.e., the medium where the light is coming from, often air) must be written in the first line, then the layer prescription from the outermost layer to the one closest to the substrate and, finally, the substrate itself. For the immersing medium and substrate, the thickness is not considered (semi-infinite substrate configuration), but the material must always be associated with a thickness number (even though it is not taken into account) to follow the required data format. It is possible to specify if the thickness written in the prescription file is optical or physical when calling the library-specific function. A sketch of the cross-section of the three-layer coating considered in this paper is represented in Fig. 1 as an example.
To simulate the proposed design, the prescription text file must be written as follows: where the 0 associated with the immersing medium and with the substrate can be substituted by any other integer number. The optical properties of the materials are stored in a .json file containing the complex refractive index N, consisting of the refractive index (n) and extinction coefficient (k) which are combined as follows
Glass | 0 |
SiO2 | 50 |
TiO2 | 60 |
SiO2 | 70 |
Glass | 0 |
To perform the various calculations, a wavelength interval must be chosen with a specific sampling: the user must therefore choose the minimum wavelength (${\lambda _{min}}$), the maximum wavelength (${\lambda _{max}}$), and the sampling interval (s) between these two extremes. The program creates an array of $\left( {\frac{{{\lambda_{max}}\; - \; {\lambda_{min}}}}{s}} \right)$ data points equally spaced by s and ranging from ${\lambda _{min}}$ to ${\lambda _{max}}$. The program automatically interpolates linearly the available refractive index data to generate the required refractive index values at the chosen wavelengths. If the range requested by the user is wider than the one supplied by the json file, the script takes the extreme available value and copies it for all the missing steps. It is possible to manually insert additional refractive index data or generate additional json files by following the syntax below
{
“material": “insert the name of the material”,
“wavelength": [${\lambda _1}$, ${\lambda _2}$, ${\lambda _3}$,…, ${\lambda _n}$],
“real": [${a_1}$, ${a_2}$, ${a_3}$,…, ${a_n}$],
“complex": [${b_1}$, ${b_2}$, ${b_3}$,…, ${b_n}$]
},
where the values are sorted in increasing wavelength order. Clearly, the size of all three lists (wavelength, real, complex) must be the same. To correctly call the function, the code must be similar to the following:
test = pocal.pocal(’filename.txt’, incident angle, minimum wavelength, maximum wavelength, spacing, reference wavelength, optical thickness (‘True’ or ‘False’), refinement (‘None’ or ‘reflectance’ or ‘transmittance’)
where the filename is the name of the text file containing the prescription of the chosen design (the path can be attached too, if the file is in a different folder), the incident angle is considered within the surrounding medium, minimum wavelength, maximum wavelength and resolution are, respectively, ${\lambda _{min}}$, ${\lambda _{max}}$, s, while reference wavelength is the value that must be used for the desired reference wavelength. The Boolean variable optical thickness can be True if the thickness values written in the prescription file are optical thickness values, or False, if the numbers refer to the physical thickness (in nm). The last parameter, refinement, can be None, when no refinement is desired, while it can be switched to ‘transmittance’ or ‘reflectance’ depending on the property to be optimized.
3. Results
3.1 Reflectance, transmittance, absorbance
The calculation of the spectral reflectance, transmittance, and absorbance is one of the main aims of the library; in fact, those 3 parameters play a key role in the characterization of the optical properties of thin films, especially when the goal is to design filters or beam splitters [28]. The library allows performing an exact ‘a priori’ analysis by considering all the parameters of the multilayer stack. To achieve this goal, the program uses the well-known characteristic matrix approach [28]. The characteristic matrix for the i-th layer can be written as
The reflectance, transmittance, and absorbance can be obtained using the following formulae
Using the library, it is possible to calculate the reflectance, transmittance, and absorbance of the multilayer stack. It is important to select the correct polarization (s or p) by using different function names. When the incident angle is 0 degrees, both give the same result. The code to be used is
test.s_polarization(’reflectance’, True, True)
test.s_polarization(’transmittance’, True, True)
test.s_polarization(’absorbance’, True, True)
test.p_polarization(’reflectance’, True, True)
test.p_polarization(’transmittance’, True, True)
test.p_polarization(’absorbance’, True, True)
where the first ‘True’ allows the user to save the text file with the wavelength and the optical parameter chosen, and the second one saves the plot as a png image. In order not to save one of these two outputs, the Boolean ‘False’ must be used. For example, it is possible to use the code to calculate the reflectance and transmittance of the design proposed in Fig. 1, with an incident angle of 40° (to show data for both s- and p-polarization). The outputs can be seen in Fig. 2 panels A, B (s- and p-pol reflectance), C, D (s- and p-pol transmittance), and E, F (s- and p-pol absorbance). In the 6 panels, the data obtained with the library (red) are plotted together with the data coming from the Essential Macleod software (blue dots) for the same design. In all figures, the differences between the sets of spectra are almost negligible (1 nm resolution for POCAL spectra and 20 nm for Essential Macleod spectra).
3.2 Phase shift
The phase shift represents the variation of the phase of the light impinging on the stack induced by the optical properties of each layer of the stack. The phase shift can be calculated for both the transmitted and reflected light. Once the quantities B and C are calculated (see Eq. (7)), it is straightforward to get the phase shift for both the reflected and transmitted light. The formulae are
The code to get the reflected and transmitted phase shift in s and p polarization is the following
test.s_polarization(’reflected_phase_shift’, True, True)
test.s_polarization(’transmitted_phase_shift’, True, True)
test.p_polarization(’reflected_phase_shift’, True, True)
test.p_polarization(’transmitted_phase_shift’, True, True)
And the data are reported in Fig. 3.
3.3 Group delay and group delay dispersion
The phase shift does not carry useful information to characterize the behavior of the multilayer coating. Two quantities directly connected to the phase shift are the group delay (GD) and the group delay dispersion (GDD). The GD represents the delay introduced by the assembly to the reflected or transmitted light when a pulse train is propagating through the multilayer. The GDD, on the other side, is the modification of the bandwidth of the finite pulse sent through the stack caused by the alteration of the GD. GD and GDD can be obtained using the phase shift $\phi $ and angular frequency $\omega = 2\pi c/\lambda $:
To calculate them, the code that must be typed is the following (only illustrated for s-polarization).
test.s_polarization(’GD_trans’, True, True)
test.s_polarization(’GDD_trans’, True, True)
resulting in the results presented in Fig. 4.
It is possible to detect a difference in the data from Essential Macleod and the one provided by POCAL. This is due to the way the GD and GDD are calculated. In particular, the big spikes at approximately 1000 nm for the reflectance and approximately 500 nm for the transmittance graphs are ascribable to the derivative numerical calculation. In fact, the phase shift functions represented in Fig. 3 show discontinuities. These functions are derived to obtain the GD and GDD represented in Fig. 4 and clearly the discontinuities are derived too, leading to the discussed big spikes. It is possible that Essential Macleod calculates differently the GD and GDD functions, or that it does not consider the discontinuities. Apart from this aspect, the data are comparable.
3.4 Color analysis
When dealing with a multilayer coating, an important parameter is the color of the transmitted or reflected light: in fact, several applications (such as dichroic coatings or band-pass filters) involve a precise tuning of the color [29,30]. The library can perform an extensive analysis of the color appearance of the selected multilayer prescription. To determine the color of an object, some standard illuminants, as well as standard observers, must be considered. The CIE (International Commission on Illumination) is the international authority that determined and strictly classified the optical properties of the illuminants and the observer. A standard illuminant is a purely theoretical quantity, having a spectral power distribution (SPD) formulated by CIE [31]. They are extremely beneficial as they provide a basis to compare and contrast colors under different illumination conditions. Three illuminants (A, D65, E) and two standard observers (CIE 1931 and CIE 1964) have been implemented in the library. Illuminant A is representative of incandescent light with a correlated color temperature of 2856 K, illuminant D65 represents average daylight (ultraviolet region excluded), with a correlated color temperature of 6504 K, while illuminant E represents a radiator emitting equal energy with a constant SPD inside the visible spectrum. The different illuminants allow to simulate different illumination conditions to which the stack may be exposed, and the standard observers represent the chromatic response of an average person with normal color vision. The illuminants introduced are visually represented in Fig. 5(A) while the standard observers are represented in Fig. 5(B).
The colors can be represented in the CIE 1931 XYZ, CIE xyY, CIELAB, and the CIE 1976 u′v′ color space. The CIE 1931 XYZ color space was created based on the color-matching experiments of W. David Wright and J. Guild [32,33]. The XYZ color space covers all types of color sensations of an average person and is used as a standard reference space to define many color spaces. The Y in XYZ color space refers to luminance and X and Y convey information about the reaction of cone cells in the human eye to different frequency light waves. The xyY color space which is often widely used to represent commonly used colors can be easily derived from the XYZ color space as follows:
The CIELAB color space is also known as the L*a*b* color space. While the L in L*a*b* color space represents perceptual lightness, the remaining components a* and b* are used for the colors red, yellow, blue, and green. The CIELAB color space can be derived from the CIEXYZ space as given below:
Here (${X_r},{Y_r},{Z_r}$) refer to the reference white and the function f is given by:
The CIE 1976 u′v′ color space is based on the CIE XYZ color space. It attempts to incorporate perceptual uniformity which means the color space is more human-friendly.
In this paper, we compare the color results obtained via POCAL with the data from Essential Macleod in the XYZ color space. We show the results from reflected color perceived by different observers (CIE 1931 and CIE 1964) exploiting different illuminants (A, D65, E) in s-polarization for a 40° incident angle. The code to be used to extract the data is the following
test.s_polarizationcolor(‘reflectance’, observer_type = ‘CIE_1964’, illuminant_type = ‘A’, color_space = ‘XYZ’)
The parameter ‘observer_type’ can take arguments ‘CIE_1931’ or ‘CIE_1964’, the parameter ‘illuminant_type’ can be set equal to ‘A’, ‘D65’, or ‘E’, while the different color spaces can be selected by the ‘color_space’ parameter to a value between ‘XYZ’, ‘xyY’, ‘LAB’, or ‘LUV’. The results from the comparisons are reported in Table 1.
3.5 Admittance diagram
The admittance diagram is a graphic technique to determine the optical properties of the considered multilayer. This technique is intended to analyze the multilayer during its deposition on the substrate until it is fully manufactured. As each layer increases its thickness, the admittance at different stages of the process is calculated. This technique is not as precise as calculating numerically all the optical properties, but it represents a fast way to get an overall idea about the performance of the multilayer stack. The admittance diagrams are calculated for a specific wavelength; therefore, no wavelength iteration is needed. Equation (7) is still valid and, once B and C are calculated, it is possible to obtain the x and y coordinates to plot the admittance diagrams, according to the formulae
The code to be used to generate the admittance diagram of the stack is the following:
test.admittance(True, True)
where the thickness of a single step is equal to the thickness of the layer divided by 1000.
Figure 6 shows the result for the 3-layer design that was introduced before, taking into account a reference wavelength of 600 nm. The starting point of the locus is $({\alpha ,0} )$, where $\alpha $ is the admittance of the substrate. As the thickness of each dielectric layer is increased, a semicircle is traced for each quarter-wave thickness. For the design in consideration, all the individual layer thicknesses remain less than a quarter-wave $\left( {\frac{{600}}{4} = 150\; nm} \right)$. Thus, for each thickness an arc shorter than a semicircle is traced. It may be noted that the arcs are circular for dielectrics while absorbing materials lead to spirals.
3.6 Electric field
Light interacts with materials via the electric field. When passing through the multilayer stack, light can undergo the formation of standing waves which can affect the overall amplitude and position (along the thin film) of the electric field inside each of the materials composing the multilayer coating. The analysis of the electric field plays an important role if the optoelectronics properties of the coatings must be fine-tuned.
The equation
By using the code
test.electricField(True, True)
it is possible to have an insight into the magnitude of the electric field inside the multilayer stack.
Figure 7 shows the electric field for the considered design, assuming that the irradiance of the incident wave $({{I_{inc}}} )$ is equal to 1 $\frac{W}{{{m^2}}}$ for these calculations. The magnitude of the electric field can be used as an indicator of the absorption losses, as a function of the sample depth. By convention, it is plotted against the optical distance within the medium (in full-width optical thickness units) [34].
3.7 Refinement
The goal of the refinement process is to return as output a coating design with a desired reflectance or transmittance. In the implemented refinement process, the number of layers, the layer materials, and their order is kept constant, while the layer thickness of each layer composing the stack is treated as a variable for the optimization problem (considering an average of the s- and p-polarizations for non-normal incidence). The function to be optimized $f(x )\; $ is defined as the root-mean-square deviation between the user-specified and calculated transmittance or reflectance by the algorithm. The goal of the refinement process is to minimize the described function and find the local minimum $\mathop {\min }\limits_\textrm{x} f(x )$, where
test.refinement(10)
The function call results in the execution of the refinement process, after which the optimized coating design is written in the file ‘refined_prescription.txt’. As an example, we consider again the 3-layer coating considered earlier and try to optimize the reflectance towards a step function (reflectance = 0% up to a wavelength of 800 nm and a reflectance = 30% from 850 nm onwards). The result after calling the refinement function is shown in Fig. 8, for a 0° incident angle:
As can be seen in Fig. 8, POCAL allows for a good refinement, which shows only slight differences compared to the Essential Macleod result, using the simplex algorithm. The slight differences may be ascribable to the different optimization engines used by the two approaches. Both refined designs are much closer to the desired target with respect to the initial configuration. The generated designs (both POCAL and Essential Macleod) are reported in Table 2. It can be observed that the two designs differ considerably in terms of their physical thickness. Both optimization techniques rely on finding a local minimum to the objective function instead of a global minimum. In POCAL the user can fine-tune the results by adjusting the tolerance, which typically leads to finding new local minima for the analyzed objective function. Obviously, modifying the tolerance parameter affects the computation time; therefore, the user is free to tune this value depending on available time and hardware performances.
4. Discussion
The results obtained with the POCAL Python library are in most of the cases comparable with the Essential Macleod software, which represents the best-in-class software to perform optical coating analysis. Only in the GD and GDD calculations the results are, for some local points, discording, but this is ascribable to the mathematical calculation of the derivatives in the discontinuous region. In addition, the refinement process is solid and gives reasonable results once the targets are correctly set.
5. Conclusions
In this paper, we have presented POCAL, the open-source Python Optical Coating Analysis Library. Thanks to this library, it is possible to simulate both fundamental optical properties of thin-film multilayer coatings (such as reflectance and transmittance) and more advanced features (e.g., group delay dispersion or electric field inside the multilayer stack). The library can be easily included in other Python scripts, allowing for a fast implementation of more complex optical simulations. The users can perform a coating refinement, allowing them to reach the desired reflectance/transmittance goals by automatically performing minor changes to the thicknesses of the layers composing the stack. Moreover, we have shown how the results calculated utilizing POCAL correspond with the data obtained via the Essential Macleod software, demonstrating the reliability of the package. Although multiple features have been implemented in the library, in the future we would like to add certain additional functionalities that may help users to perform a wider variety of calculations, including a model for finite substrate thickness, functional dispersion models, and a global optimization algorithm.
Funding
VLAIO - Flux50 & Catalisti - ICON (HBC.2020.2451).
Acknowledgments
All the people involved in the realization of the library have been listed in the author list.
Disclosures
The authors declare no conflicts of interest.
Data availability
Data underlying the results presented in this paper are available in [26,27].
References
1. H. A. Macleod, “Monitoring of optical coatings,” Appl. Opt. 20(1), 82 (1981). [CrossRef]
2. R. R. Willey, “Optical thickness monitoring sensitivity improvement using graphical methods,” Appl. Opt. 26(4), 729 (1987). [CrossRef]
3. J. H. Apfel, “Graphics in Optical Coating Design,” Appl. Opt. 11(6), 1303 (1972). [CrossRef]
4. R. W. Phillip and A. F. Bleikolm, “Optical coatings for document security,” Appl. Opt. 35(28), 5529 (1996). [CrossRef]
5. A. V. Tikhonravov and M. K. Trubetskov, “Modern design tools and a new paradigm in optical coating design,” Appl. Opt. 51(30), 7319 (2012). [CrossRef]
6. Ö Duyar and H. Z. Durusoy, “Design and preparation of antireflection and reflection optical coatings,” Turkish J. Phys. 28, 139–144 (2004).
7. X. Zhu, Q. Zhu, H. Wu, and C. Chen, “Optical design of LED-based automotive headlamps,” Opt. Laser Technol. 45, 262–266 (2013). [CrossRef]
8. M. Holder, C. Linnhoff, P. Rosenberger, and H. Winner, “The fourier tracing approach for modeling automotive radar sensors,” Proc. Int. Radar Symp. 2019-June, 1–8 (2019). [CrossRef]
9. H. Friedrich, J. Günther, A. Dietrich, M. Scherbaum, H. P. Seidel, and P. Slusallek, “Exploring the use of ray tracing for future games,” Proc. - Sandbox Symp. 2006 ACM SIGGRAPH Video Game Symp. Sandbox ‘06 1, 41–50 (2006).
10. H. B. Eldeeb, E. Eso, E. A. Jarchlo, S. Zvanovec, M. Uysal, Z. Ghassemlooy, and J. Sathian, “Vehicular VLC: A Ray Tracing Study Based on Measured Radiation Patterns of Commercial Taillights,” IEEE Photonics Technol. Lett. 33(16), 904–907 (2021). [CrossRef]
11. J. Wesner, F. Eisenkramer, J. Heil, and T. Sure, “Improved polarization ray tracing of thin-film optical coatings,” Nov. Opt. Syst. Des. Optim. VII 5524, 261 (2004). [CrossRef]
12. A. Russell and A. Chipman, “Polarization Ray Tracing to Instrumental Instrumental Polarization Polarization Function The The Instrumental Polarization,” (1987).
13. S. Larouche and L. Martinu, “OpenFilters: Open-source software for the design, optimization, and synthesis of optical filters,” Appl. Opt. 47(13), C219–230 (2008). [CrossRef]
14. K. R. Srinath, “Python -The Fastest Growing Programming Language,” Int. Res. J. Eng. Technol. 4, 354–357 (2017).
15. S. Raschka, J. Patterson, and C. Nolet, “Machine learning in python: Main developments and technology trends in data science, machine learning, and artificial intelligence,” Information 11(4), 193 (2020). [CrossRef]
16. I. Stancin and A. Jovic, “An overview and comparison of free Python libraries for data mining and big data analysis,” 2019 42nd Int. Conv. Inf. Commun. Technol. Electron. Microelectron. MIPRO 2019 - Proc. 977–982 (2019).
17. B. Margolis and K. Lyons, “ndsplines: A Python Library for Tensor-Product B-Splines of Arbitrary Dimension,” J. Open Source Softw. 4(42), 1745 (2019). [CrossRef]
18. M. G. Poolman, “ScrumPy: Metabolic modelling with Python,” IEE Proc. Syst. Biol. 153(5), 375–378 (2006). [CrossRef]
19. K. Klementiev and R. Chernikov, “Powerful scriptable ray tracing package xrt,” Adv. Comput. Methods X-Ray Opt. III 9209, 92090A (2014). [CrossRef]
20. J. Herrera, C. A. Guerrero, M. R. Najera, A. Sotelo-Burke, and I. Plauchu-Frayn, “KrakenOS: Python-based general exact ray tracing library,” Opt. Eng. 61(01), 1–41 (2022). [CrossRef]
21. “Luxpop,” http://www.luxpop.com/.
22. “FreeSnell,” https://people.csail.mit.edu/jaffer/FreeSnell/.
23. “openTMM,” https://pypi.org/project/openTMM/.
24. H. a. Macleod, “Optical Coating Design with the Essential Macleod,” 226 (2007).
25. “OpTaliX,” http://www.optenso.com/index.html.
26. T. Fontanot, U. Bhaumik, and R. Kishore, “POCAL Library,” GitHub, (2023), [accessed 20 March 2023] https://github.com/tommasofontanot/pocal/tree/main/resources
27. T. Fontanot, U. Bhaumik, and R. Kishore, “POCAL Library,” GitHub, (2023), https://github.com/tommasofontanot/pocal
28. H. A. Macleod, Thin-Film Optical Filters, CRC Press (CRC Press, 2010).
29. S. Zhao, Z. Shao, A. Huang, S. Bao, H. Luo, S. Ji, P. Jin, and X. Cao, “Dynamic full-color tunability of high-performance smart windows utilizing absorption-emission effect,” Nano Energy 89, 106297 (2021). [CrossRef]
30. O. Gómez, E. Perales, E. Chorro, F. J. Burgos, V. Viqueira, M. Vilaseca, F. M. Martínez-Verdú, and J. Pujol, “Visual and instrumental assessments of color differences in automotive coatings,” Color Res. Appl. 41, 384–391 (2016). [CrossRef]
31. J. Schanda, Colorimetry: Understanding the CIE System, John Wiley (John Wiley & Sons, 2007).
32. W. D. Wright, “A re-determination of the trichromatic coefficients of the spectral colors,” Trans. Opt. Soc. 30(4), 141–164 (1929). [CrossRef]
33. J. Guild, “The Colorimetric Properties of the Spectrum,” Phil. Trans. R. Soc. Lond. A 230(681-693), 149–187 (1931). [CrossRef]
34. J. H. Apfel, “Optical coating design with reduced electric field intensity,” Appl. Opt. 16(7), 1880 (1977). [CrossRef]