{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n", " Optimizing a double-layer MgF2/Ta2O5 anti-reflection coating for \"infinitely-thick\"
\n", "GaAs. Minimize reflection * AM0 spectrum (weighted reflectance).
\n", "To use yabox for the DE, we need to define a class which sets up the problem and has an
\n", "'evaluate' function within it, which will actually calculate the value we are trying to
\n", "minimize for each set of parameters.
\n", "The \"if __name__ == \"__main__\" construction is used to avoid issues with parallel processing on Windows.
\n", "The issues arises because the multiprocessing module uses a different process on Windows than on UNIX
\n", "systems which will throw errors if this construction is not used.
\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from typing import Sequence\n", "import numpy as np\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from solcore import material\n", "from solcore.optics.tmm import OptiStack, calculate_rat\n", "from solcore.light_source import LightSource" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Import the DE implementations" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from solcore.optimization import PDE" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class CalcRDiff:\n", " def __init__(self):\n", " \"\"\" Make the wavelength and the materials n and k data object attributes.\n", " The n and k data are extracted from the Solcore materials rather than using\n", " the material directly because there is currently an issue with using the\n", " Solcore material class in parallel computations.\n", " \"\"\"\n", " self.wl = np.linspace(250, 900, 700)\n", " self.MgF2 = [\n", " self.wl,\n", " material(\"MgF2\")().n(self.wl * 1e-9),\n", " material(\"MgF2\")().k(self.wl * 1e-9),\n", " ]\n", " # This is Ta2O5 from the SOPRA database included in Solcore\n", " self.Ta2O5 = [\n", " self.wl,\n", " material(\"TAOX1\")().n(self.wl * 1e-9),\n", " material(\"TAOX1\")().k(self.wl * 1e-9),\n", " ]\n", " self.GaAs = [\n", " 1000,\n", " self.wl,\n", " material(\"GaAs\")().n(self.wl * 1e-9),\n", " material(\"GaAs\")().k(self.wl * 1e-9),\n", " ]\n", "\n", " # assuming an AM0 spectrum\n", " spectr = LightSource(\n", " source_type=\"standard\",\n", " version=\"AM1.5g\",\n", " x=self.wl,\n", " output_units=\"photon_flux_per_m\",\n", " concentration=1,\n", " ).spectrum(self.wl * 1e-9)[1]\n", "\n", " # Only want to use spectrum to weight reflectivity result so don't care about\n", " # absolute values\n", " self.spectrum = spectr / max(spectr)\n", " def reflectance(self, x: Sequence[float]) -> float:\n", " \"\"\" Create a list with the format [thickness, wavelengths, n_data, k_data] for\n", " each layer.\n", " This is one of the acceptable formats in which OptiStack can take information\n", " (look at the Solcore documentation or at the OptiStack code for more info)\n", " We set no_back_reflection to True because we DO NOT want to include reflection\n", " at the back surface (assume GaAs is infinitely thick)\n", " :param x: List with the thicknesses of the two layers in the ARC.\n", " :return: Array with the reflection at each wavelength\n", " \"\"\"\n", " arc = [[x[0]] + self.MgF2, [x[1]] + self.Ta2O5, self.GaAs]\n", " full_stack = OptiStack(arc, no_back_reflection=True)\n", " return calculate_rat(full_stack, self.wl, no_back_reflection=True)[\"R\"]\n", " def evaluate(self, x: Sequence[float]) -> float:\n", " \"\"\" Returns the number the DA algorithm has to minimise.\n", " In this case, this is the weighted reflectance\n", " :param x: List with the thicknesses of the two layers in the ARC.\n", " :return: weighted reflectance\n", " \"\"\"\n", " return sum(self.reflectance(x) * self.spectrum)\n", " def plot(self, x: Sequence[float]) -> None:\n", " \"\"\" Plots the reflectance\n", " :param x: List with the thicknesses of the two layers in the ARC.\n", " :return: None\n", " \"\"\"\n", " plt.figure()\n", " plt.plot(self.wl, self.reflectance(x))\n", " plt.xlabel(\"Wavelength (nm)\")\n", " plt.ylabel(\"R\")\n", " plt.show()\n", " def plot_weighted(self, x: Sequence[float]) -> None:\n", " \"\"\" Plots the weighted reflectance.\n", " :param x: List with the thicknesses of the two layers in the ARC.\n", " :return: None\n", " \"\"\"\n", " plt.figure()\n", " plt.plot(self.wl, self.reflectance(x) * self.spectrum)\n", " plt.xlabel(\"Wavelength (nm)\")\n", " plt.ylabel(\"R weighted by AM0\")\n", " plt.show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def main():" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ " # number of iterations for Differential Evolution\n", " maxiters = 100\n", "\n", " # class the DE algorithm is going to use, as defined above\n", " PDE_class = CalcRDiff()\n", "\n", " # Pass the function which will be minimized to the PDE (parallel differential evolution)\n", " # solver. PDE calculates the results for each population in parallel to speed up the\n", " # overall process\n", " PDE_obj = PDE(PDE_class.evaluate, bounds=[[0, 400], [0, 400]], maxiters=maxiters)\n", "\n", " # solve, i.e. minimize the problem\n", " res = PDE_obj.solve()\n", " \"\"\"\n", " PDE_obj.solve() returns 5 things:\n", " - res[0] is a list of the parameters which gave the minimized value\n", " - res[1] is that minimized value\n", " - res[2] is the evolution of the best population (the best population from each \n", " iteration\n", " - res[3] is the evolution of the minimized value, i.e. the fitness over each iteration\n", " - res[4] is the evolution of the mean fitness over the iterations\n", " \"\"\"\n", " best_pop = res[0]\n", " print(\"Parameters for best result:\", best_pop, res[1])\n", " PDE_class.plot(best_pop)\n", " PDE_class.plot_weighted(best_pop)\n", "\n", " # plot evolution of the best and mean fitness of the population per iteration\n", " plt.figure()\n", " plt.plot(res[3], \"-k\", label=\"Best fitness\")\n", " plt.plot(res[4], \"-r\", label=\"Mean fitness\")\n", " plt.xlabel(\"iteration\")\n", " plt.ylabel(\"fitness\")\n", " plt.legend()\n", " plt.show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if __name__ == '__main__':\n", " main()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.4" } }, "nbformat": 4, "nbformat_minor": 2 }