def plot(self, x): # x is a list with all the layer thicknesses, except for the Ge (which is kept as a thick substrate) # this does basically what evaluate() does, but plots the results SC = [[x[0]] + self.MgF2, [x[1]] + self.Ta2O5, [x[2]] + self.InGaP, [x[3]] + self.GaAs, [x[4]] + self.SiGeSn, [300e3] + self.Ge] full_stack = OptiStack(SC, no_back_reflection=False) RAT = calculate_rat(full_stack, self.wl, no_back_reflection=False, coherent=False, coherency_list=['c', 'c', 'c', 'c', 'c', 'i']) A_InGaP = RAT['A_per_layer'][3] A_GaAs = RAT['A_per_layer'][4] A_SiGeSn = RAT['A_per_layer'][5] A_Ge = RAT['A_per_layer'][6] plt.figure() plt.plot(self.wl, A_InGaP, label='InGaP') plt.plot(self.wl, A_GaAs, label='A_GaAs') plt.plot(self.wl, A_SiGeSn, label='SiGeSn') plt.plot(self.wl, A_Ge, label='Ge') plt.plot(self.wl, RAT['T'], label='T') plt.plot(self.wl, RAT['R'], label='R') plt.legend() plt.xlabel('Wavelength (nm)') plt.show()
def test_tmm_rcwa_structure_comparison(pol, angle): import numpy as np from solcore import si, material from solcore.structure import Layer from solcore.solar_cell import SolarCell from solcore.optics.tmm import calculate_rat, OptiStack from solcore.optics.rcwa import calculate_rat_rcwa InGaP = material('GaInP')(In=0.5) GaAs = material('GaAs')() Ge = material('Ge')() Ag = material('Ag')() Air = material('Air')() Al2O3 = material('Al2O3')() wavelengths = np.linspace(250, 1900, 500) size = ((100, 0), (0, 100)) ARC = [Layer(si('80nm'), Al2O3)] solar_cell = SolarCell(ARC + [ Layer(material=InGaP, width=si('400nm')), Layer(material=GaAs, width=si('4000nm')), Layer(material=Ge, width=si('3000nm')) ], substrate=Ag) solar_cell_OS = OptiStack(solar_cell, no_back_reflection=False, substrate=solar_cell.substrate) rcwa_result = calculate_rat_rcwa(solar_cell, size, 2, wavelengths, Air, Ag, theta=angle, phi=angle, pol=pol, parallel=True) tmm_result = calculate_rat(solar_cell_OS, wavelengths, angle, pol, no_back_reflection=False) assert tmm_result['A_per_layer'][1:-1] == approx( rcwa_result['A_per_layer'].T) assert tmm_result['R'] == approx(rcwa_result['R']) assert tmm_result['T'] == approx(rcwa_result['T']) assert np.sum(tmm_result['A_per_layer'][1:-1].T, 1) + tmm_result['R'] + tmm_result['T'] == approx(1) assert np.sum(rcwa_result['A_per_layer'], 1) + rcwa_result['R'] + rcwa_result['T'] == approx(1)
def plot_weighted(self, x): # this does basically what evaluate() does, but plots the reflectivity weighted by the AM0 solar spectrum ARC = [[x[0]] + self.MgF2, [x[1]] + self.Ta2O5, self.GaAs] full_stack = OptiStack(ARC, no_back_reflection=True) RAT = calculate_rat(full_stack, self.wl, no_back_reflection=True) spect_n = self.spectrum / np.max(self.spectrum) plt.figure() plt.plot(self.wl, RAT['R'] * spect_n) plt.xlabel('Wavelength (nm)') plt.ylabel('R weighted by AM0') plt.show()
def plot(self, x): # this does basically what evaluate() does, but plots the reflectivity ARC = [[x[0]] + self.MgF2, [x[1]] + self.Ta2O5, self.GaAs] full_stack = OptiStack(ARC, no_back_reflection=True) RAT = calculate_rat(full_stack, self.wl, no_back_reflection=True) plt.figure() plt.plot(self.wl, RAT['R']) plt.xlabel('Wavelength (nm)') plt.ylabel('R') plt.show()
def reflectance(self, x: Sequence[float]) -> float: """ Create a list with the format [thickness, wavelengths, n_data, k_data] for each layer. This is one of the acceptable formats in which OptiStack can take information (look at the Solcore documentation or at the OptiStack code for more info) We set no_back_reflection to True because we DO NOT want to include reflection at the back surface (assume GaAs is infinitely thick) :param x: List with the thicknesses of the two layers in the ARC. :return: Array with the reflection at each wavelength """ arc = [[x[0]] + self.MgF2, [x[1]] + self.Ta2O5, self.GaAs] full_stack = OptiStack(arc, no_back_reflection=True) return calculate_rat(full_stack, self.wl, no_back_reflection=True)["R"]
def evaluate(self, x): # x[0] = MgF2 thickness (anti-reflection coating) # x[1] = Ta2O5 thickness (anti-reflection coating) # x[2] = InGaP (top junction) thickness # x[3] = GaAs (second junction) thickness # x[4] = SiGeSn (third junction) thickness # keep the thickness of the bottom cell constant; from an optical point of view, this should be infinitely thick SC = [[x[0]] + self.MgF2, [x[1]] + self.Ta2O5, [x[2]] + self.InGaP, [x[3]] + self.GaAs, [x[4]] + self.SiGeSn, [300e3] + self.Ge] #, [x[5]] + self.Ge] # create the OptiStack full_stack = OptiStack(SC, no_back_reflection=False) # calculate reflection, transmission, and absorption in each layer. We are specifying that the last layer, # a very thick Ge substrate, should be treated incoherently, otherwise we would see very narrow, unphysical oscillations # in the R/A/T spectra. RAT = calculate_rat(full_stack, self.wl, no_back_reflection=False, coherent=False, coherency_list=['c', 'c', 'c', 'c', 'c', 'i']) # extract absorption per layer A_InGaP = RAT['A_per_layer'][3] A_GaAs = RAT['A_per_layer'][4] A_SiGeSn = RAT['A_per_layer'][5] A_Ge = RAT['A_per_layer'][6] ## calculate photo-generated currents using the AM1.5 G spectrum for each layer Jsc_InGaP = 0.1 * q * np.trapz(A_InGaP * self.spectr, self.wl) Jsc_GaAs = 0.1 * q * np.trapz(A_GaAs * self.spectr, self.wl) Jsc_SiGeSn = 0.1 * q * np.trapz(A_SiGeSn * self.spectr, self.wl) Jsc_Ge = 0.1 * q * np.trapz(A_Ge * self.spectr, self.wl) # find the limiting current by checking which junction has the lowest current. Then take the negative since # we need to minimize (not maximize) limiting_Jsc = -min([Jsc_InGaP, Jsc_GaAs, Jsc_SiGeSn, Jsc_Ge]) return limiting_Jsc
def evaluate(self, x): # create a list of layers with the format [thickness, wavelengths, n_data, k_data] for each layer. # This is one of the acceptable formats in which OptiStack can take information (look at the Solcore documentation # or at the OptiStack code for more info ARC = [[x[0]] + self.MgF2, [x[1]] + self.Ta2O5, self.GaAs] # create the OptiStack. We set no_back_reflection to True because we DO NOT want to include reflection at the back surface # (assume GaAs is infinitely thick) full_stack = OptiStack(ARC, no_back_reflection=True) # calculate reflection, transmission, and absorption in each layer. RAT = calculate_rat(full_stack, self.wl, no_back_reflection=True) R_weighted = RAT['R'] * self.spectrum # 'evaluate' should return a single number. The DE algorithm tries to minimize this number. return sum(R_weighted)
def evaluate(self, x): # create a list of layers with the format [thickness, wavelengths, n_data, k_data] for each layer. # This is one of the acceptable formats in which OptiStack can take information (look at the Solcore documentation # or at the OptiStack code for more info SC = [[x[0]] + self.MgF2, [x[1]] + self.Ta2O5, [x[2]] + self.InGaP, [x[3]] + self.GaAs, [x[4]] + self.SiGeSn, [300e3] + self.Ge] #, [x[5]] + self.Ge] # create the OptiStack. We set no_back_reflection to False because we DO want to include reflection at the back surface # (thin-film interference due to reflection at the SiGeSn/Ge interface) full_stack = OptiStack(SC, no_back_reflection=False) # calculate reflection, transmission, and absorption in each layer. We are specifying that the last layer, # a very thick Ge substrate, should be treated incoherently, otherwise we would see very narrow, unphysical oscillations # in the R/A/T spectra. RAT = calculate_rat(full_stack, self.wl, no_back_reflection=False, coherent=False, coherency_list=['c', 'c', 'c', 'c', 'c', 'i']) # extract absorption per layer A_InGaP = RAT['A_per_layer'][3] A_GaAs = RAT['A_per_layer'][4] A_SiGeSn = RAT['A_per_layer'][5] A_Ge = RAT['A_per_layer'][6] ## calculate currents using the AM1.5 G spectrum for each layer Jsc_InGaP = 0.1 * q * np.trapz(A_InGaP * self.spectr, self.wl) Jsc_GaAs = 0.1 * q * np.trapz(A_GaAs * self.spectr, self.wl) Jsc_SiGeSn = 0.1 * q * np.trapz(A_SiGeSn * self.spectr, self.wl) Jsc_Ge = 0.1 * q * np.trapz(A_Ge * self.spectr, self.wl) # find the limiting current by checking which junction has the lowest current. Then take the negative since # we need to minimize (not maximize) limiting_Jsc = -min([Jsc_InGaP, Jsc_GaAs, Jsc_SiGeSn, Jsc_Ge]) return limiting_Jsc
def test_tmm_rcwa_structure_profile_comparison(pol, angle): import numpy as np from solcore import si, material from solcore.structure import Layer from solcore.solar_cell import SolarCell from solcore.optics.tmm import calculate_rat, calculate_absorption_profile, OptiStack from solcore.optics.rcwa import calculate_rat_rcwa, calculate_absorption_profile_rcwa InGaP = material('GaInP')(In=0.5) GaAs = material('GaAs')() Ge = material('Ge')() Ag = material('Ag')() Air = material('Air')() wavelengths = np.linspace(250, 1900, 8) size = ((100, 0), (0, 100)) solar_cell = SolarCell([ Layer(material=InGaP, width=si('400.5nm')), Layer(material=GaAs, width=si('500nm')), Layer(material=Ge, width=si('1000nm')) ], substrate=Ag) solar_cell_OS = OptiStack(solar_cell, no_back_reflection=False, substrate=solar_cell.substrate) rcwa_result = calculate_rat_rcwa(solar_cell, size, 2, wavelengths, Air, Ag, theta=angle, phi=angle, pol=pol, parallel=True) tmm_result = calculate_rat(solar_cell_OS, wavelengths, angle, pol, no_back_reflection=False) tmm_profile = calculate_absorption_profile(solar_cell_OS, wavelengths, no_back_reflection=False, angle=angle, pol=pol, RAT_out=tmm_result, steps_size=2) rcwa_profile = calculate_absorption_profile_rcwa( solar_cell, size, 2, wavelengths, rcwa_result['A_pol'], theta=angle, phi=angle, pol=pol, incidence=Air, substrate=solar_cell.substrate, parallel=True, steps_size=2) assert tmm_profile['position'] == approx(rcwa_profile['position'], abs=2e-6) assert tmm_profile['absorption'] == approx(rcwa_profile['absorption'], abs=2e-6)