def test_TMM_ellipsometry(): GaAs = material("GaAs")(T=300) my_structure = Structure( [Layer(si(3000, "nm"), material=GaAs), Layer(si(300, "um"), material=GaAs)] ) wavelength = np.linspace(450, 1100, 300) idx = np.argmin(abs(wavelength - 800)) angles = [60, 65, 70] out = calculate_ellipsometry(my_structure, wavelength, angle=angles) data = ( 22.2849089096, 181.488417672, 16.4604621886, 182.277656469, 9.10132195668, 184.509752582, ) for i in range(len(angles)): assert data[2 * i] == approx(out["psi"][idx, i]) assert data[2 * i + 1] == approx(out["Delta"][idx, i])
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 test_BL_correction(): wl = np.linspace(800, 950, 4) * 1e-9 GaAs = material("GaAs")() thick_cell = SolarCell([Layer(material=GaAs, width=si("20um"))]) opts = State() opts.position = None prepare_solar_cell(thick_cell, opts) position = np.arange(0, thick_cell.width, 1e-9) opts.position = position opts.recalculate_absorption = True opts.no_back_reflexion = False opts.BL_correction = False opts.wavelength = wl solve_tmm(thick_cell, opts) no_corr = thick_cell.absorbed opts.BL_correction = True solve_tmm(thick_cell, opts) with_corr = thick_cell.absorbed assert with_corr == approx( np.array([6.71457872e-01, 6.75496354e-01, 2.09738887e-01, 0])) assert no_corr == approx( np.array([6.71457872e-01, 6.75496071e-01, 2.82306407e-01, 0]))
def test_calculate_absorption_profile_rcwa(): import numpy as np from solcore import material, si from solcore.structure import Layer, Structure from solcore.absorption_calculator.rigorous_coupled_wave import calculate_rat_rcwa, calculate_absorption_profile_rcwa T = 300 Air = material("Air")(T=T) TiO2 = material("TiO2", sopra=True)(T=T) # for the nanoparticles GaAs = material("GaAs")(T=T) th = 50 NP_layer = Layer( si(th, "nm"), Air, geometry=[{ "type": "ellipse", "mat": TiO2, "center": (200, 200), "halfwidths": [70, 100], "angle": 30 }], ) np_struct = Structure([NP_layer]) wl = np.linspace(300, 1000, 10) rat_np = calculate_rat_rcwa(np_struct, size=((400, 0), (0, 400)), orders=10, wavelength=wl, substrate=GaAs, incidence=Air) A_output = rat_np['A_pol'] step_size = 2 dist = np.arange(0, th, step_size) result = calculate_absorption_profile_rcwa(np_struct, size=((400, 0), (0, 400)), orders=10, wavelength=wl, rat_output_A=A_output, steps_size=step_size) parallel_result = calculate_absorption_profile_rcwa(np_struct, size=((400, 0), (0, 400)), orders=10, wavelength=wl, rat_output_A=A_output, parallel=True, steps_size=step_size) assert sorted(list(result.keys())) == ["absorption", "position"] assert sorted(list(parallel_result.keys())) == ["absorption", "position"] assert len(result["position"]) == len(dist) assert len(parallel_result["position"]) == len(dist) assert result["absorption"] == approx(parallel_result["absorption"], abs=1e-5)
def get_indices(self, wl): """ Returns the complex refractive index of the stack. :param wl: Wavelength of the light in nm. :return: A list with the complex refractive index of each layer, including the semi-infinite front and back layers and, opionally, the back absorbing layer used to suppress back surface relfexion. """ out = [] wl_m = solcore.si(wl, 'nm') if hasattr(wl, 'size'): n0 = np.ones_like(wl, dtype=complex) else: n0 = 1 for i in range(self.num_layers): out.append(self.n_data[i](wl_m) + self.k_data[i](wl_m) * 1.0j) if self.no_back_reflexion: return [n0] + out + [ self.n_data[-1](wl_m) + self._k_absorbing(wl_m) * 1.0j, n0 ] else: return [n0] + out + [n0]
def test_TMM_absorption_profile(): GaAs = material("GaAs")(T=300) my_structure = Structure([ Layer(si(3000, "nm"), material=GaAs), Layer(si(300, "um"), material=GaAs) ]) out = calculate_absorption_profile(my_structure, np.array([800]), z_limit=3000, steps_size=20) data_path = Path(__file__).parent / "data" / "absorption_profile.txt" data = tuple(np.loadtxt(data_path)) assert all([d == approx(o) for d, o in zip(data, out["absorption"][0])])
def evaluate(self, x): GaAs = material('GaAs_WVASE')() Air = material('Air')() InAlP = material('InAlP_WVASE')() InGaP = material('InGaP_WVASE')() Ag = material('Ag_Jiang')() # MgF2 = material('MgF2')() # Ta2O5 = material('410', nk_db=True)() SiN = material('SiN_SE')() # print('SiN thickness', x[2]*x[1], 'Ag th', (1-x[1])*x[2]) grating1 = [Layer(si(x[2] * x[1], 'nm'), SiN)] grating2 = [ Layer(si((1 - x[1]) * x[2], 'nm'), SiN, geometry=[{ 'type': 'circle', 'mat': Ag, 'center': (0, 0), 'radius': x[3], 'angle': 0 }]) ] solar_cell = SolarCell([ Layer(material=InGaP, width=si('19nm')), Layer(material=GaAs, width=si(x[0], 'nm')), Layer(material=InAlP, width=si('18nm')) ] + grating1 + grating2, substrate=Ag) S4_setup = rcwa_structure(solar_cell, self.size, self.orders, self.options, Air, Ag) RAT = S4_setup.calculate() EQE_sim = 0.9 * 100 * (RAT['A_layer'][:, 0] + RAT['A_layer'][:, 1]) # least squares? residual = np.sum((EQE_sim - self.EQE_meas)**2) return residual
def test_substrate_presence_profile(): wavelength = np.linspace(300, 800, 3) * 1e-9 GaAs = material("GaAs")(T=300) my_structure = SolarCell([Layer(si(700, "nm"), material=GaAs)], substrate=GaAs) solar_cell_solver( my_structure, "optics", user_options={ "wavelength": wavelength, "optics_method": "TMM", "no_back_reflection": False, }, ) z_pos = np.linspace(0, my_structure.width, 10) profile_subs = my_structure[0].absorbed(z_pos) my_structure = SolarCell([Layer(si(700, "nm"), material=GaAs)]) solar_cell_solver( my_structure, "optics", user_options={ "wavelength": wavelength, "optics_method": "TMM", "no_back_reflection": False, }, ) profile_nosubs = my_structure[0].absorbed(z_pos) profile = np.vstack((profile_subs, profile_nosubs)) data_path = Path( __file__).parent / "data" / "substrate_presence_profile.csv" expected = np.loadtxt(data_path, delimiter=",") assert profile.shape == expected.shape assert profile == approx(expected)
def default_GaAs(T): # We create the other materials we need for the device window = material('AlGaAs')(T=T, Na=5e24, Al=0.8) p_GaAs = material('GaAs')(T=T, Na=1e24) n_GaAs = material('GaAs')(T=T, Nd=8e22) bsf = material('GaAs')(T=T, Nd=2e24) output = Junction([ Layer(width=si('30nm'), material=window, role="Window"), Layer(width=si('150nm'), material=p_GaAs, role="Emitter"), Layer(width=si('3000nm'), material=n_GaAs, role="Base"), Layer(width=si('200nm'), material=bsf, role="BSF") ], sn=1e6, sp=1e6, T=T, kind='PDD') return output
def junction(nd_top, na_top, nd_bottom, na_bottom): from solcore.structure import Junction, Layer from solcore import si, material from solcore.solar_cell import SolarCell from solcore.constants import vacuum_permittivity from solcore.solar_cell_solver import prepare_solar_cell from solcore.optics import solve_beer_lambert Lp = np.power(10, np.random.uniform(-8, -6)) Ln = np.power(10, np.random.uniform(-8, -6)) AlInP = material("AlInP") InGaP = material("GaInP") window_material = AlInP(Al=0.52) top_cell_n_material = InGaP( In=0.48, Nd=nd_top, Na=na_top, hole_diffusion_length=Lp, electron_diffusion_length=Ln, ) top_cell_p_material = InGaP( In=0.48, Nd=nd_bottom, Na=na_bottom, hole_diffusion_length=Lp, electron_diffusion_length=Ln, ) rel_perm = np.random.uniform(1, 20) for mat in [top_cell_n_material, top_cell_p_material]: mat.permittivity = rel_perm * vacuum_permittivity n_width = np.random.uniform(500, 1000) * 1e-9 p_width = np.random.uniform(3000, 5000) * 1e-9 test_junc = SolarCell([ Junction( [ Layer(si("25nm"), material=window_material, role="window"), Layer(n_width, material=top_cell_n_material, role="emitter"), Layer(p_width, material=top_cell_p_material, role="base"), ], sn=1, sp=1, kind="DA", ) ]) options = da_options() options.light_source = da_light_source() prepare_solar_cell(test_junc, options) solve_beer_lambert(test_junc, options) return test_junc, options
def test_substrate_presence_A(): wavelength = np.linspace(300, 800, 3) * 1e-9 GaAs = material("GaAs")(T=300) my_structure = SolarCell([Layer(si(700, "nm"), material=GaAs)], substrate=GaAs) solar_cell_solver( my_structure, "optics", user_options={ "wavelength": wavelength, "optics_method": "TMM", "no_back_reflexion": False, }, ) z_pos = np.linspace(0, my_structure.width, 10) A_subs = my_structure[0].layer_absorption my_structure = SolarCell([Layer(si(700, "nm"), material=GaAs)]) solar_cell_solver( my_structure, "optics", user_options={ "wavelength": wavelength, "optics_method": "TMM", "no_back_reflexion": False, }, ) A_nosubs = my_structure[0].layer_absorption A = np.vstack((A_subs, A_nosubs)) A_data = np.array([[0.56610281, 0.62692985, 0.41923175], [0.56610281, 0.62711355, 0.37837737]]) assert all([d == approx(o) for d, o in zip(A, A_data)])
def test_44_TMM_ellipsometry(self): GaAs = material('GaAs')(T=300) my_structure = Structure([ Layer(si(3000, 'nm'), material=GaAs), Layer(si(300, 'um'), material=GaAs), ]) wavelength = np.linspace(450, 1100, 300) idx = np.argmin(abs(wavelength - 800)) angles = [60, 65, 70] out = calculate_ellipsometry(my_structure, wavelength, angle=angles) data = (22.2849089096, 181.488417672, 16.4604621886, 182.277656469, 9.10132195668, 184.509752582) for i in range(len(angles)): self.assertAlmostEqual(data[2 * i], out['psi'][idx, i]) self.assertAlmostEqual(data[2 * i + 1], out['Delta'][idx, i])
def test_inc_coh_tmm(): GaInP = material("GaInP")(In=0.5) GaAs = material("GaAs")() Ge = material("Ge")() optical_struct = SolarCell([ Layer(material=GaInP, width=si("5000nm")), Layer(material=GaAs, width=si("200nm")), Layer(material=GaAs, width=si("5um")), Layer(material=Ge, width=si("50um")), ]) wl = np.linspace(400, 1200, 5) * 1e-9 options = State() options.wavelength = wl options.optics_method = "TMM" options.no_back_reflection = False options.BL_correction = True options.recalculate_absorption = True c_list = [ ["c", "c", "c", "c"], ["c", "c", "c", "i"], ["c", "i", "i", "c"], ["i", "i", "i", "i"], ] results = [] for i1, cl in enumerate(c_list): options.coherency_list = cl solar_cell_solver(optical_struct, "optics", options) results.append(optical_struct.absorbed) A_calc = np.stack(results) A_data = np.array( [[0.5742503, 0.67956899, 0.73481184, 0.725372, 0.76792856], [0.5742503, 0.67956899, 0.73481184, 0.725372, 0.76792856], [0.5742503, 0.67956899, 0.73474943, 0.70493469, 0.70361194], [0.5742503, 0.67956899, 0.70927724, 0.71509221, 0.71592772]]) assert A_calc == approx(A_data)
def AlGaAs(T): # We create the other materials we need for the device window = material("AlGaAs")(T=T, Na=5e24, Al=0.8) p_AlGaAs = material("AlGaAs")(T=T, Na=1e24, Al=0.4) n_AlGaAs = material("AlGaAs")(T=T, Nd=8e22, Al=0.4) bsf = material("AlGaAs")(T=T, Nd=2e24, Al=0.6) output = Junction( [ Layer(width=si("30nm"), material=window, role="Window"), Layer(width=si("150nm"), material=p_AlGaAs, role="Emitter"), Layer(width=si("1000nm"), material=n_AlGaAs, role="Base"), Layer(width=si("200nm"), material=bsf, role="BSF"), ], sn=1e6, sp=1e6, T=T, kind="PDD", ) return output
def test_64_quantum_mechanics_schrodinger(self): bulk = material("GaAs")(T=293) barrier = material("GaAsP")(T=293, P=0.1) bulk.strained = False barrier.strained = True top_layer = Layer(width=si("30nm"), material=bulk) inter = Layer(width=si("3nm"), material=bulk) barrier_layer = Layer(width=si("15nm"), material=barrier) bottom_layer = top_layer E = np.linspace(1.15, 1.5, 300) * q alfas = np.zeros((len(E), 6)) alfas[:, 0] = E / q alpha_params = { "well_width": si("7.2nm"), "theta": 0, "eps": 12.9 * vacuum_permittivity, "espace": E, "hwhm": si("6meV"), "dimensionality": 0.16, "line_shape": "Gauss" } QW = material("InGaAs")(T=293, In=0.2) QW.strained = True well_layer = Layer(width=si("7.2nm"), material=QW) my_structure = Structure( [top_layer, barrier_layer, inter] + 1 * [well_layer, inter, barrier_layer, inter] + [bottom_layer], substrate=bulk) band_edge, bands = QM.schrodinger(my_structure, quasiconfined=0, num_eigenvalues=20, alpha_params=alpha_params, calculate_absorption=True) for key in band_edge['E']: for i in range(len(band_edge['E'][key])): band_edge['E'][key][i] = solcore.asUnit( band_edge['E'][key][i], 'eV') * 1000 band_edge['E'][key][i] = round(band_edge['E'][key][i]) Ehh = np.all(np.equal(band_edge['E']['Ehh'], my_energies['Ehh'])) Elh = np.all(np.equal(band_edge['E']['Elh'], my_energies['Elh'])) Ee = np.all(np.equal(band_edge['E']['Ee'], my_energies['Ee'])) idx = 100 out = [band_edge['alpha'][0][idx] / q, band_edge['alpha'][1][idx]] # Test over the energies self.assertTrue(Ehh and Elh and Ee) # Test over the absorption coefficent at a given energy for i, data in enumerate(out): self.assertAlmostEqual(out[i], my_absorption[i])
def plot_R(obj, x, icol): cols = sns.cubehelix_palette(len(use_orders), start=.5, rot=-.9, reverse=True) GaAs = material('GaAs_WVASE')() Air = material('Air')() InAlP = material('InAlP_WVASE')() InGaP = material('InGaP_WVASE')() Ag = material('Ag_Jiang')() # MgF2 = material('MgF2')() # Ta2O5 = material('410', nk_db=True)() SiN = material('SiN_SE')() R_data = np.loadtxt('Talbot_precursor_R.csv', delimiter=',') grating1 = [Layer(si(x[2] * x[1], 'nm'), SiN)] grating2 = [ Layer(si((1 - x[1]) * x[2], 'nm'), SiN, geometry=[{ 'type': 'circle', 'mat': Ag, 'center': (0, 0), 'radius': x[3], 'angle': 0 }]) ] solar_cell = SolarCell([ Layer(material=GaAs, width=si('25nm')), Layer(material=InGaP, width=si('19nm')), Layer(material=GaAs, width=si(x[0], 'nm')), Layer(material=InAlP, width=si('18nm')) ] + grating1 + grating2, substrate=Ag) S4_setup = rcwa_structure(solar_cell, obj.size, obj.orders, obj.options, Air, Ag) RAT = S4_setup.calculate() total_A = np.sum(RAT['A_layer'], axis=1) # plt.figure() plt.plot(S4_setup.wavelengths * 1e9, RAT['R'], label=str(obj.orders), color=cols[icol]) return S4_setup.wavelengths * 1e9, interp1d(R_data[:, 0], R_data[:, 1])( S4_setup.wavelengths * 1e9)
def AlGaAs(): from solcore import material from solcore.structure import Layer, Junction from solcore import si T = 298 # We create the other materials we need for the device window = material("AlGaAs")(T=T, Na=5e24, Al=0.8) p_AlGaAs = material("AlGaAs")(T=T, Na=1e24, Al=0.4) n_AlGaAs = material("AlGaAs")(T=T, Nd=8e22, Al=0.4) bsf = material("AlGaAs")(T=T, Nd=2e24, Al=0.6) return Junction( [ Layer(width=si("30nm"), material=window, role="Window"), Layer(width=si("150nm"), material=p_AlGaAs, role="Emitter"), Layer(width=si("1000nm"), material=n_AlGaAs, role="Base"), Layer(width=si("200nm"), material=bsf, role="BSF"), ], sn=1e6, sp=1e6, T=T, kind="PDD", )
def test_TMM_rat(): GaAs = material("GaAs")(T=300) my_structure = Structure([Layer(si(3000, "nm"), material=GaAs)]) wavelength = np.linspace(450, 1100, 300) idx = np.argmin(abs(wavelength - 800)) out = calculate_rat( my_structure, wavelength, coherent=True, no_back_reflexion=False ) out = (out["R"][idx], out["A"][idx], out["T"][idx]) data = (0.33328918841743332, 0.65996607786373396, 0.0067447337188326914) assert all([d == approx(o) for d, o in zip(data, out)])
def prepare_test_cell(): from solcore import material, si from solcore.structure import Junction, Layer, TunnelJunction from solcore.solar_cell import SolarCell GaAs = material("GaAs")() MgF2 = material("MgF2")() TiO2 = material("TiO2")() Ge = material("Ge")() widths = np.random.rand(9) * 200 solar_cell = SolarCell([ Layer(si(widths[0], "nm"), material=MgF2), Layer(si(widths[1], "nm"), material=TiO2), Junction( [ Layer(si(widths[2], "nm"), material=GaAs, role="window"), Layer(si(widths[3], "nm"), material=GaAs, role="emitter"), Layer(si(widths[4], "nm"), material=GaAs, role="base"), ], kind="DA", ), TunnelJunction([ Layer(si(widths[5], "nm"), material=GaAs), Layer(si(widths[6], "nm"), material=GaAs), ]), Junction( [ Layer(si(widths[7], "nm"), material=Ge, role="emitter"), Layer(si(widths[8], "nm"), material=Ge, role="base"), ], kind="PDD", ), ]) return solar_cell, widths
def _add_raw_nk_layer(self, layer): """ Adds a layer to the end (bottom) of the stack. The layer must be defined as a list containing the layer thickness in nm, the wavelength, the n and the k data as array-like objects. :param layer: The new layer to add as [thickness, wavelength, n, k] :return: None """ # We make sure that the wavelengths are increasing, revering the arrays otherwise. if layer[1][0] > layer[1][-1]: layer[1] = layer[1][::-1] layer[2] = layer[2][::-1] layer[3] = layer[3][::-1] self.widths.append(layer[0]) if len(layer) >= 5: self.models.append(layer[4]) c = solcore.si(layer[5][0], 'nm') w = solcore.si(layer[5][1], 'nm') d = layer[5][2] # = 0 for increasing, =1 for decreasing def mix(x): out = 1 + np.exp(-(x - c) / w) out = d + (-1)**d * 1 / out return out n_data = np_cache(lambda x: self.models[-1].n_and_k(x) * mix(x) + ( 1 - mix(x)) * interp1d(x=solcore.si(layer[1], 'nm'), y=layer[2], fill_value=layer[2][-1])(x)) k_data = np_cache(lambda x: interp1d(x=solcore.si(layer[1], 'nm'), y=layer[3], fill_value=layer[3][-1])(x)) self.n_data.append(n_data) self.k_data.append(k_data) else: self.models.append([]) self.n_data.append( np_cache( interp1d(x=solcore.si(layer[1], 'nm'), y=layer[2], fill_value=layer[2][-1]))) self.k_data.append( np_cache( interp1d(x=solcore.si(layer[1], 'nm'), y=layer[3], fill_value=layer[3][-1])))
def get_indices(self, wl): """ Returns the complex refractive index of the stack. :param wl: Wavelength of the light in nm. :return: A list with the complex refractive index of each layer, including the semi-infinite front and back layers and, opionally, the back absorbing layer used to suppress back surface relfexion. """ out = [] wl_m = solcore.si(wl, 'nm') if hasattr(self, 'n_sub'): n1 = self.n_sub(wl_m) + self.k_sub(wl_m) * 1.0j else: if hasattr(wl, 'size'): n1 = np.ones_like(wl, dtype=complex) else: n1 = 1 # incidence medium! if hasattr(self, 'n_sup'): n0 = self.n_sup( wl_m ) #+ self.k_sup(wl_m)*1.0j ignore complex part for now to avoid errors else: if hasattr(wl, 'size'): n0 = np.ones_like(wl, dtype=complex) else: n0 = 1 for i in range(self.num_layers): out.append(self.n_data[i](wl_m) + self.k_data[i](wl_m) * 1.0j) # substrate irrelevant if no_back_reflection = True if self.no_back_reflection: return [n0] + out + [ self.n_data[-1](wl_m) + self._k_absorbing(wl_m) * 1.0j, n1 ] # look at last entry in stack, # make high;y absorbing layer based on it. else: return [n0] + out + [n1]
def absorptance_detailed_balance(junction): """ Calculates the absorptance of the junction in the detailed balanced case. If it has not been calculated before, provided as input, it uses a "top hat" absorptance with the absorption edge at Eg and magnitude A. Note that while the junction.absorptance represents the potential fraction of light that can be absorbed at a given energy, the junction.absorbed represents the actual fraction of input light that is absorbed. For detailed balanced calculations, these two are equivalent to the IQE and EQE respectively because carrier collection is perfect, but that will not be the case, in general. :param junction: Junction object of kind "DB" """ try: if not hasattr(junction, 'absorptance'): wlg = si(1240 / junction.Eg, 'nm') A = min(junction.A, 1) def absorptance(wl): return A * (wl < wlg) junction.absorptance = absorptance except AttributeError as err: raise AttributeError( 'ERROR calculating absorptance for the detailed balance Junction kind.\nJunction is missing one essential argument: {}' .format(err))
def test_42_TMM_rat(self): GaAs = material('GaAs')(T=300) my_structure = Structure([ Layer(si(3000, 'nm'), material=GaAs), ]) wavelength = np.linspace(450, 1100, 300) idx = np.argmin(abs(wavelength - 800)) out = calculate_rat(my_structure, wavelength, coherent=True, no_back_reflexion=False) out = (out['R'][idx], out['A'][idx], out['T'][idx]) data = (0.33328918841743332, 0.65996607786373396, 0.0067447337188326914) for i in range(3): self.assertAlmostEqual(data[i], out[i])
def test_calculate_rat_rcwa(): import numpy as np from solcore import material, si from solcore.structure import Layer, Structure from solcore.absorption_calculator.rigorous_coupled_wave import calculate_rat_rcwa T = 300 Air = material("Air")(T=T) TiO2 = material("TiO2", sopra=True)(T=T) # for the nanoparticles GaAs = material("GaAs")(T=T) NP_layer = Layer( si("50nm"), Air, geometry=[{ "type": "circle", "mat": TiO2, "center": (200, 200), "radius": 50 }], ) np_struct = Structure([NP_layer]) wl = np.linspace(300, 1000, 150) rat_np = calculate_rat_rcwa(np_struct, size=((400, 0), (0, 400)), orders=10, wavelength=wl, substrate=GaAs, incidence=Air) assert sorted(list( rat_np.keys())) == ["A", "A_per_layer", "A_pol", "R", "T"] for v in rat_np.values(): assert v.shape[0] == len(wl)
size = 5 nxy = 21 calc = False options = { 'wavelengths': np.arange(300, 1201, 20) * 1e-9, 'theta': 0 * np.pi / 180, 'phi': 0, 'I_thresh': 1e-2, 'nx': nxy, 'ny': nxy, 'parallel': True, 'pol': 'u', 'n_rays': 2 * nxy**2, 'depth_spacing': si('1um'), 'random_ray_position': False } if calc: flat_surf = planar_surface() triangle_surf = regular_pyramids(55, upright=True, size=size) options['avoid_edges'] = False rtstr = rt_structure(textures=[triangle_surf, flat_surf], materials=[Si], widths=[si('200um')], incidence=Air, transmission=Air) start = time()
d_vectors = ((x, 0), (0, x)) area_fill_factor = 0.36 hw = np.sqrt(area_fill_factor) * 500 front_materials = [] back_materials = [] # whether pyramids are upright or inverted is relative to front incidence. # so if the same etch is applied to both sides of a slab of silicon, one surface # will have 'upright' pyramids and the other side will have 'not upright' (inverted) # pyramids in the model surf = regular_pyramids(elevation_angle=55, size=5, upright=True) front_surf = Interface('RT_TMM', texture=surf, layers=[Layer(si('0.1nm'), Air)], name='pyramids' + str(options['n_rays'])) back_surf = Interface('Lambertian', layers=[], name='lambertian') bulk_Si = BulkLayer(201.8e-6, Si, name='Si_bulk') # bulk thickness in m SC = Structure([front_surf, bulk_Si, back_surf], incidence=Air, transmission=Air) process_structure(SC, options) results = calculate_RAT(SC, options) RAT = results[0] results_per_pass = results[1]
d_vectors = ((x, 0),(0,x)) area_fill_factor = 0.36 hw = np.sqrt(area_fill_factor)*500 front_materials = [] back_materials = [] # whether pyramids are upright or inverted is relative to front incidence. # so if the same etch is applied to both sides of a slab of silicon, one surface # will have 'upright' pyramids and the other side will have 'not upright' (inverted) # pyramids in the model surf = regular_pyramids(elevation_angle=55, upright=False) front_surf = Interface('RT_TMM', texture = surf, layers=[Layer(si('0.1nm'), Air)], name = 'inv_pyramids' + str(options['n_rays'])) back_surf = Interface('RCWA', layers=back_materials, name = 'crossed_grating_60', d_vectors=d_vectors, rcwa_orders=60) #back_surf = Interface('TMM', layers=[], name = 'planar_back', coherent=True) bulk_Si = BulkLayer(201.8e-6, Si, name = 'Si_bulk') # bulk thickness in m SC = Structure([front_surf, bulk_Si, back_surf], incidence=Air, transmission=Air) process_structure(SC, options) results = calculate_RAT(SC, options) RAT = results[0] results_per_pass = results[1]
try: num = self.junction_indices[junction] self[num].__dict__.update(kwargs) except IndexError: print( 'ERROR updating junction: The junction index must be {} or less.' .format(len(self.junction_indices))) def __call__(self, i): return self[self.junction_indices[i]] if __name__ == '__main__': window = material('AlGaAs')(T=298, Na=1e24, Al=0.8) stack = [Layer(width=si("50nm"), material=window), default_GaAs(298)] # stack = [default_GaAs(298)] my_cell = SolarCell(layers=stack) # # my_cell.append_multiple([default_GaAs(298), default_GaAs(298), default_GaAs(298)]) # print(my_cell) from solcore.poisson_drift_diffusion.DriftDiffusionUtilities import solve_pdd, default_photon_flux, \ default_wavelengths import matplotlib.pyplot as plt solve_pdd(my_cell, 'QE', vfin=1.2, vstep=0.05, light=True) QE = my_cell(0).qe
TiO2 = material('TiO2') AlInP = material("AlInP") GaInP = material("GaInP") GaAs = material('GaAs') Ge = material("Ge") Al02Ga08As = material('AlGaAs') Al08Ga02As = material('AlGaAs') # TOP CELL - GaInP ARC1 = Al2O3() ARC2 = TiO2() top_window_material = AlInP(Al=0.5) top_cell_n_material = GaInP(In=0.51, Nd=siUnits(2e18, "cm-3"), hole_diffusion_length=si("300nm")) top_cell_p_material = GaInP(In=0.51, Na=siUnits(1.5e17, "cm-3"), electron_diffusion_length=si("2um")) top_cell_TJ_material = Al08Ga02As(Al=0.8) for mat in [top_cell_n_material, top_cell_p_material]: mat.band_gap = material('GaInP')(In=0.51).band_gap mat.eff_mass_hh_z = material('GaInP')(In=0.51).eff_mass_hh_z mat.eff_mass_electron = material('GaInP')(In=0.51).eff_mass_electron mat.relative_permittivity = 11.75 all_materials.append(ARC1) all_materials.append(ARC2) all_materials.append(top_window_material) all_materials.append(top_cell_n_material)
from solcore import si from solcore import material from solcore.solar_cell import SolarCell, Layer, Junction from solcore.solar_cell_solver import solar_cell_solver, default_options import numpy as np from scipy.interpolate import interp1d import matplotlib.pyplot as plt T = 300 wavelengths_optics = np.linspace(300, 1200, 800) * 1e-9 Si = material("Si") SiO2 = material("SiO2")() n_material = Si(T=T, Nd=si(1e21, "cm-3"), hole_diffusion_length=si("50um"), electron_mobility=50e-4, relative_permittivity=11.68) p_material = Si(T=T, Na=si(1e16, "cm-3"), electron_diffusion_length=si("150um"), hole_mobility=400e-4, relative_permittivity=11.68) ARC_width = si("100nm") n_material_width = si("500nm") p_material_width = si("50um") solar_cell = SolarCell([ Layer(width=ARC_width, material=SiO2),