Example #1
0
    def evaluate(self, x):

        light_source = LightSource(source_type='standard', version='AM1.5g')

        wl = np.linspace(300, 1850, 500) * 1e-9

        solar_cell = self.make_cell(x)

        position = [1e-10] * 10 + [5e-8]

        V = np.linspace(0, 3.5, 300)
        solar_cell_solver(solar_cell,
                          'iv',
                          user_options={
                              'voltages': V,
                              'light_iv': True,
                              'wavelength': wl,
                              'mpp': True,
                              'light_source': light_source,
                              'optics_method': 'TMM',
                              'BL_correction': True,
                              'position': position
                          })

        efficiency = solar_cell.iv["Eta"]

        # print('Efficiency =', efficiency)

        return -efficiency
Example #2
0
def test_light_iv(AlGaAs, light_source):
    import numpy as np
    from solcore.solar_cell import SolarCell, default_GaAs
    from solcore import material
    from solcore.solar_cell_solver import solar_cell_solver

    expected = np.array([
        142.68025180227374,
        2.519346556870366,
        0.9169672186977382,
        329.61395441947565,
        2.347826086956522,
        140.3911287342211,
        0.3294918264376029,
    ])

    T = AlGaAs.T
    Vin = np.linspace(-2, 2.61, 201)
    V = np.linspace(0, 2.6, 300)

    substrate = material("GaAs")(T=T)

    my_solar_cell = SolarCell([AlGaAs, default_GaAs(T)],
                              T=T,
                              R_series=0,
                              substrate=substrate)
    solar_cell_solver(
        my_solar_cell,
        "iv",
        user_options={
            "T_ambient": T,
            "db_mode": "boltzmann",
            "voltages": V,
            "light_iv": True,
            "wavelength": light_source.x,
            "optics_method": "BL",
            "mpp": True,
            "internal_voltages": Vin,
            "light_source": light_source,
        },
    )

    output = [
        my_solar_cell.iv.Isc,
        my_solar_cell.iv.Voc,
        my_solar_cell.iv.FF,
        my_solar_cell.iv.Pmpp,
        my_solar_cell.iv.Vmpp,
        my_solar_cell.iv.Impp,
        my_solar_cell.iv.Eta,
    ]

    assert np.array(output) == approx(expected, rel=1e-2)
Example #3
0
def solve_MJ(EgBot, EgMid, EgTop):
    db_junction0 = Junction(kind='DB', T=T, Eg=EgBot, A=1, R_shunt=np.inf, n=3.5)
    db_junction1 = Junction(kind='DB', T=T, Eg=EgMid, A=1, R_shunt=np.inf, n=3.5)
    db_junction2 = Junction(kind='DB', T=T, Eg=EgTop, A=1, R_shunt=np.inf, n=3.5)

    my_solar_cell = SolarCell([db_junction2, db_junction1, db_junction0], T=T, R_series=0)

    solar_cell_solver(my_solar_cell, 'iv',
                      user_options={'T_ambient': T, 'db_mode': 'top_hat', 'voltages': V, 'light_iv': True,
                                    'internal_voltages': np.linspace(-6, 5, 1100), 'wavelength': wl,
                                    'mpp': True, 'light_source': light})

    return my_solar_cell
Example #4
0
def test_light_iv():
    answer = [
        142.68025180227374,
        2.519346556870366,
        0.9169672186977382,
        329.61395441947565,
        2.347826086956522,
        140.3911287342211,
        0.3294918264376029,
    ]
    with tempfile.TemporaryDirectory(prefix="tmp",
                                     suffix="_sc3TESTS") as working_directory:
        filename = os.path.join(working_directory, "solcore_log.txt")
        PDD.log(filename)

        my_solar_cell = SolarCell([AlGaAs(T), default_GaAs(T)],
                                  T=T,
                                  R_series=0,
                                  substrate=substrate)
        solar_cell_solver(
            my_solar_cell,
            "iv",
            user_options={
                "T_ambient": T,
                "db_mode": "boltzmann",
                "voltages": V,
                "light_iv": True,
                "wavelength": wl,
                "optics_method": "BL",
                "mpp": True,
                "internal_voltages": Vin,
                "light_source": light_source,
            },
        )

        output = [
            my_solar_cell.iv.Isc,
            my_solar_cell.iv.Voc,
            my_solar_cell.iv.FF,
            my_solar_cell.iv.Pmpp,
            my_solar_cell.iv.Vmpp,
            my_solar_cell.iv.Impp,
            my_solar_cell.iv.Eta,
        ]

    for i in range(len(output)):
        assert output[i] == approx(answer[i])
Example #5
0
def test_quantum_efficiency(AlGaAs, light_source):
    import numpy as np
    from solcore.solar_cell import SolarCell, default_GaAs
    from solcore import material
    from solcore.solar_cell_solver import solar_cell_solver

    expected = np.array([
        0.9866334968497021,
        2.1512408472022467e-14,
        0.9779769012349702,
        0.03506561338387434,
    ])
    T = AlGaAs.T
    Vin = np.linspace(-2, 2.61, 201)
    V = np.linspace(0, 2.6, 300)

    substrate = material("GaAs")(T=T)

    my_solar_cell = SolarCell([AlGaAs, default_GaAs(T)],
                              T=T,
                              R_series=0,
                              substrate=substrate)

    solar_cell_solver(
        my_solar_cell,
        "qe",
        user_options={
            "T_ambient": T,
            "db_mode": "boltzmann",
            "voltages": V,
            "light_iv": True,
            "wavelength": light_source.x,
            "optics_method": "BL",
            "mpp": True,
            "internal_voltages": Vin,
            "light_source": light_source,
        },
    )

    output = [
        my_solar_cell[0].eqe(500e-9),
        my_solar_cell[0].eqe(800e-9),
        my_solar_cell[1].eqe(700e-9),
        my_solar_cell[1].eqe(900e-9),
    ]
    assert np.array(output) == approx(expected, abs=1e-3)
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 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)])
Example #8
0
def test_quantum_efficiency():
    answer = [
        0.9866334968497021,
        2.1512408472022467e-14,
        0.9779769012349702,
        0.03506561338387434,
    ]
    with tempfile.TemporaryDirectory(prefix="tmp",
                                     suffix="_sc3TESTS") as working_directory:
        filename = os.path.join(working_directory, "solcore_log.txt")
        PDD.log(filename)

        my_solar_cell = SolarCell([AlGaAs(T), default_GaAs(T)],
                                  T=T,
                                  R_series=0,
                                  substrate=substrate)

        solar_cell_solver(
            my_solar_cell,
            "qe",
            user_options={
                "T_ambient": T,
                "db_mode": "boltzmann",
                "voltages": V,
                "light_iv": True,
                "wavelength": wl,
                "optics_method": "BL",
                "mpp": True,
                "internal_voltages": Vin,
                "light_source": light_source,
            },
        )

        output = [
            my_solar_cell[0].eqe(500e-9),
            my_solar_cell[0].eqe(800e-9),
            my_solar_cell[1].eqe(700e-9),
            my_solar_cell[1].eqe(900e-9),
        ]

    for i in range(len(output)):
        assert output[i] == approx(answer[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)
Example #10
0
def solve_MJ(EgBot, EgMid, EgTop):
    db_junction0 = Junction(kind="DB",
                            T=T,
                            Eg=EgBot,
                            A=1,
                            R_shunt=np.inf,
                            n=3.5)
    db_junction1 = Junction(kind="DB",
                            T=T,
                            Eg=EgMid,
                            A=1,
                            R_shunt=np.inf,
                            n=3.5)
    db_junction2 = Junction(kind="DB",
                            T=T,
                            Eg=EgTop,
                            A=1,
                            R_shunt=np.inf,
                            n=3.5)

    my_solar_cell = SolarCell([db_junction2, db_junction1, db_junction0],
                              T=T,
                              R_series=0)

    solar_cell_solver(
        my_solar_cell,
        "iv",
        user_options={
            "T_ambient": T,
            "db_mode": "top_hat",
            "voltages": V,
            "light_iv": True,
            "internal_voltages": np.linspace(-6, 5, 1100),
            "wavelength": wl,
            "mpp": True,
            "light_source": light,
        },
    )

    return my_solar_cell
Example #11
0
    def test_92_light_iv(self):
        answer = [
            142.68025180227374, 2.519346556870366, 0.9169672186977382,
            329.61395441947565, 2.347826086956522, 140.3911287342211,
            0.3294918264376029
        ]
        with tempfile.TemporaryDirectory(
                prefix="tmp", suffix="_sc3TESTS") as working_directory:
            filename = os.path.join(working_directory, 'solcore_log.txt')
            PDD.log(filename)

            my_solar_cell = SolarCell([AlGaAs(T), default_GaAs(T)],
                                      T=T,
                                      R_series=0,
                                      substrate=substrate)
            solar_cell_solver(my_solar_cell,
                              'iv',
                              user_options={
                                  'T_ambient': T,
                                  'db_mode': 'boltzmann',
                                  'voltages': V,
                                  'light_iv': True,
                                  'wavelength': wl,
                                  'optics_method': 'BL',
                                  'mpp': True,
                                  'internal_voltages': Vin,
                                  'light_source': light_source
                              })

            output = [
                my_solar_cell.iv.Isc, my_solar_cell.iv.Voc,
                my_solar_cell.iv.FF, my_solar_cell.iv.Pmpp,
                my_solar_cell.iv.Vmpp, my_solar_cell.iv.Impp,
                my_solar_cell.iv.Eta
            ]

        for i in range(len(output)):
            self.assertAlmostEqual(output[i], answer[i])
Example #12
0
    def test_92_light_iv(self):
        answer = [
            141.434980729, 2.46952886616, 0.91434377329, 319.359951949,
            2.29565217391, 139.115130584, 0.319241623262
        ]
        with tempfile.TemporaryDirectory(
                prefix="tmp", suffix="_sc3TESTS") as working_directory:
            filename = os.path.join(working_directory, 'solcore_log.txt')
            PDD.log(filename)

            my_solar_cell = SolarCell([AlGaAs(T), default_GaAs(T)],
                                      T=T,
                                      R_series=0,
                                      substrate=substrate)
            solar_cell_solver(my_solar_cell,
                              'iv',
                              user_options={
                                  'T_ambient': T,
                                  'db_mode': 'boltzmann',
                                  'voltages': V,
                                  'light_iv': True,
                                  'wavelength': wl,
                                  'optics_method': 'BL',
                                  'mpp': True,
                                  'internal_voltages': Vin,
                                  'light_source': light_source
                              })

            output = [
                my_solar_cell.iv.Isc, my_solar_cell.iv.Voc,
                my_solar_cell.iv.FF, my_solar_cell.iv.Pmpp,
                my_solar_cell.iv.Vmpp, my_solar_cell.iv.Impp,
                my_solar_cell.iv.Eta
            ]

        for i in range(len(output)):
            self.assertAlmostEqual(output[i], answer[i])
Example #13
0
    def test_93_qe(self):
        answer = [
            0.9866334968497021, 2.1512408472022467e-14, 0.9779769012349702,
            0.03506561338387434
        ]
        with tempfile.TemporaryDirectory(
                prefix="tmp", suffix="_sc3TESTS") as working_directory:
            filename = os.path.join(working_directory, 'solcore_log.txt')
            PDD.log(filename)

            my_solar_cell = SolarCell([AlGaAs(T), default_GaAs(T)],
                                      T=T,
                                      R_series=0,
                                      substrate=substrate)

            solar_cell_solver(my_solar_cell,
                              'qe',
                              user_options={
                                  'T_ambient': T,
                                  'db_mode': 'boltzmann',
                                  'voltages': V,
                                  'light_iv': True,
                                  'wavelength': wl,
                                  'optics_method': 'BL',
                                  'mpp': True,
                                  'internal_voltages': Vin,
                                  'light_source': light_source
                              })

            output = [
                my_solar_cell[0].eqe(500e-9), my_solar_cell[0].eqe(800e-9),
                my_solar_cell[1].eqe(700e-9), my_solar_cell[1].eqe(900e-9)
            ]

        for i in range(len(output)):
            self.assertAlmostEqual(output[i], answer[i])
Example #14
0
    def test_93_qe(self):
        answer = [
            0.9831923128532823, 1.315965183418519e-13, 0.9672990699170962,
            0.032767290395462376
        ]
        with tempfile.TemporaryDirectory(
                prefix="tmp", suffix="_sc3TESTS") as working_directory:
            filename = os.path.join(working_directory, 'solcore_log.txt')
            PDD.log(filename)

            my_solar_cell = SolarCell([AlGaAs(T), default_GaAs(T)],
                                      T=T,
                                      R_series=0,
                                      substrate=substrate)

            solar_cell_solver(my_solar_cell,
                              'qe',
                              user_options={
                                  'T_ambient': T,
                                  'db_mode': 'boltzmann',
                                  'voltages': V,
                                  'light_iv': True,
                                  'wavelength': wl,
                                  'optics_method': 'BL',
                                  'mpp': True,
                                  'internal_voltages': Vin,
                                  'light_source': light_source
                              })

            output = [
                my_solar_cell[0].eqe(500e-9), my_solar_cell[0].eqe(800e-9),
                my_solar_cell[1].eqe(700e-9), my_solar_cell[1].eqe(900e-9)
            ]

        for i in range(len(output)):
            self.assertAlmostEqual(output[i], answer[i])
Example #15
0
GaAs = material('GaAs')(T=T)

thin_GaAs = SolarCell([Layer(material=GaAs, width=si('500nm'))])

GaAs_on_substrate = SolarCell([Layer(material=GaAs, width=si('500nm'))],
                              substrate=GaAs)

wl = si(np.linspace(300, 900, 200), 'nm')

# Thin solar cell, no substrate - will get significant absorption enhancement from reflection at the GaAs/air interface at the back
# MUST specify no_back_reflection = False, so that Solcore does not automatically suppress reflections from the back
# (currently, the default setting in solcore is to suppress reflections from the back, so no_back_reflection = True
solar_cell_solver(thin_GaAs,
                  'optics',
                  user_options={
                      'wavelength': wl,
                      'optics_method': 'TMM',
                      'no_back_reflection': False
                  })
z_pos = np.linspace(0, thin_GaAs.width, 201)
profiles_thin = thin_GaAs[0].absorbed(z_pos)
# Same thin solar cell, but now on a GaAs substrate. In this case, we get the same result whether or not we specify
# no_back_reflection to be True or False, since with a GaAs on GaAs cell we don't get any reflection at the back interface anyway
solar_cell_solver(GaAs_on_substrate,
                  'optics',
                  user_options={
                      'wavelength': wl,
                      'optics_method': 'TMM'
                  })
profiles_thick = GaAs_on_substrate[0].absorbed(z_pos)
Example #16
0
solar_cell = SolarCell(
    [
        Junction([Layer(si("25nm"), material=window_material, role='window'),
                  Layer(si("100nm"), material=top_cell_n_material, role='emitter'),
                  Layer(si("600nm"), material=top_cell_p_material, role='base'),
                  ], sn=1, sp=1, kind='DA'),
        Junction([Layer(si("200nm"), material=mid_cell_n_material, role='emitter'),
                  Layer(si("3000nm"), material=mid_cell_p_material, role='base'),
                  ], sn=1, sp=1, kind='DA'),
        Junction([Layer(si("400nm"), material=bot_cell_n_material, role='emitter'),
                  Layer(si("100um"), material=bot_cell_p_material, role='base'),
                  ], sn=1, sp=1, kind='DA'),
    ], reflectivity=ref, shading=0.08, cell_area=0.7 * 0.7 / 1e4)

wl = np.linspace(300, 1800, 700) * 1e-9
solar_cell_solver(solar_cell, 'qe', user_options={'wavelength': wl})

plt.figure(1)
plt.plot(wl * 1e9, solar_cell[0].eqe(wl) * 100, 'b', label='GaInP')
plt.plot(wl * 1e9, solar_cell[1].eqe(wl) * 100, 'g', label='InGaAs')
plt.plot(wl * 1e9, solar_cell[2].eqe(wl) * 100, 'r', label='Ge')

plt.legend()
plt.ylim(0, 100)
plt.ylabel('EQE (%)')
plt.xlabel('Wavelength (nm)')

V = np.linspace(0, 3, 300)
solar_cell_solver(solar_cell, 'iv', user_options={'voltages': V, 'light_iv': True, 'wavelength': wl})

plt.figure(2)
V = np.linspace(0, 2.6, 300)
wl = np.linspace(350, 1000, 301) * 1e-9
light_source = LightSource(source_type='standard',
                           version='AM1.5g',
                           x=wl,
                           output_units='photon_flux_per_m',
                           concentration=1)

# We calculate the IV curve under illumination
solar_cell_solver(my_solar_cell,
                  'iv',
                  user_options={
                      'T_ambient': T,
                      'db_mode': 'boltzmann',
                      'voltages': V,
                      'light_iv': True,
                      'wavelength': wl,
                      'optics_method': 'BL',
                      'mpp': True,
                      'internal_voltages': Vin,
                      'light_source': light_source
                  })

# We can plot the electron and hole densities in equilibrium and at short circuit, both calculated automatically
# before calculating the IV curve
plt.figure(1)
for j in my_solar_cell.junction_indices:
    zz = my_solar_cell[j].short_circuit_data.Bandstructure[
        'x'] + my_solar_cell[j].offset
    n = my_solar_cell[j].short_circuit_data.Bandstructure['n']
    p = my_solar_cell[j].short_circuit_data.Bandstructure['p']
Example #18
0
    ["c", "c", "c", "i"],
    ["c", "i", "i", "c"],
    ["i", "i", "i", "i"],
]

titles = [
    "All coherent",
    "Bottom Ge layer explicity incoherent",
    "Both layers of GaAs junction incoherent",
    "All layers incoherent",
]

for i1, cl in enumerate(c_list):
    plt.figure(i1)
    options.coherency_list = cl
    solar_cell_solver(optical_struct, "optics", options)
    plt.plot(wl * 1e9, optical_struct[0].layer_absorption)
    plt.plot(wl * 1e9, optical_struct[1].layer_absorption)
    plt.plot(wl * 1e9, optical_struct[2].layer_absorption)
    plt.plot(wl * 1e9, optical_struct.reflected, "--")
    plt.plot(wl * 1e9, optical_struct.transmitted, "--")
    plt.plot(
        wl * 1e9,
        optical_struct[0].layer_absorption +
        optical_struct[1].layer_absorption +
        optical_struct[2].layer_absorption + optical_struct.reflected +
        optical_struct.transmitted,
    )
    plt.legend(["GaInP", "GaAs", "Ge", "R", "T", "R+A+T"], loc="upper left")
    plt.title(titles[i1])
    plt.xlabel("Wavelength (nm)")
Example #19
0
    def plot(self, x):
        light_source = LightSource(source_type='standard', version='AM1.5g')

        wl = np.linspace(300, 1850, 500) * 1e-9

        solar_cell = self.make_cell(x)

        position = [1e-10] * 10 + [5e-8]

        V = np.linspace(0, 3.5, 300)
        solar_cell_solver(solar_cell,
                          'iv',
                          user_options={
                              'voltages': V,
                              'light_iv': True,
                              'wavelength': wl,
                              'mpp': True,
                              'light_source': light_source,
                              'optics_method': 'TMM',
                              'BL_correction': True,
                              'position': position
                          })

        efficiency = solar_cell.iv["Eta"]
        pmax = solar_cell.iv["Pmpp"]
        ff = solar_cell.iv["FF"]
        voc = solar_cell.iv["Voc"]
        isc = solar_cell.iv["Isc"]

        plt.figure()

        plt.plot(V,
                 solar_cell.iv['IV'][1] / 10,
                 'k',
                 linewidth=3,
                 label='Total')
        plt.plot(V, -solar_cell[2].iv(V) / 10, 'b', label='GaInP')
        plt.plot(V, -solar_cell[3].iv(V) / 10, 'g', label='GaAs')
        plt.plot(V, -solar_cell[4].iv(V) / 10, 'r', label='SiGeSn')
        plt.plot(V, -solar_cell[5].iv(V) / 10, 'y', label='Ge')
        plt.text(2, 10, '$\eta = $' + str(round(efficiency * 100, 1)) + '%')
        plt.text(2, 8, 'Pmax=' + str(round(pmax, 1)) + 'W/m$^2$')
        plt.text(2, 9, 'FF = ' + str(round(ff * 100, 1)) + '%')
        plt.text(2, 7, 'Voc=' + str(round(voc, 1)) + 'V')
        plt.text(2, 6, 'Jsc=' + str(round(0.1 * isc, 1)) + 'mA/cm$^2$')

        plt.legend()
        plt.ylim(0, 18)
        plt.xlim(0, 3.5)
        plt.ylabel('Current (mA/cm$^2$)')
        plt.xlabel('Voltage (V)')

        plt.show()

        # print('Efficiency =', efficiency)

        solar_cell_solver(solar_cell,
                          'qe',
                          user_options={
                              'wavelength': wl,
                              'optics_method': 'TMM',
                              'BL_correction': True,
                              'position': position
                          })

        plt.figure()
        plt.plot(wl * 1e9, solar_cell[2].eqe(wl) * 100, 'b', label='InGaP')
        plt.plot(wl * 1e9, solar_cell[3].eqe(wl) * 100, 'g', label='InGaAs')
        plt.plot(wl * 1e9, solar_cell[4].eqe(wl) * 100, 'r', label='SiGeSn')
        plt.plot(wl * 1e9, solar_cell[5].eqe(wl) * 100, 'y', label='Ge')
        plt.plot(wl * 1e9,
                 solar_cell.absorbed * 100,
                 'k--',
                 label='Absorption')
        # plt.plot(wl * 1e9, solar_cell[5].eqe(wl)*100, 'y', label='Ge')

        plt.legend(loc='upper right')
        plt.xlim(290, 1850)
        plt.ylim(0, 100)
        plt.ylabel('EQE (%)')
        plt.xlabel('Wavelength (nm)')
        plt.show()
Example #20
0
plt.show()

# Compare performance as a back mirror on a GaAs 'cell'

# Solid line: absorption in GaAs
# Dashed line: absorption in Ag

GaAs = material('GaAs')()

colors = ['b', 'r', 'k', 'm', 'y']

plt.figure()
for c, Ag_mat in enumerate([Ag_Joh, Ag_McP, Ag_Hag, Ag_Rak, Ag_Sol]):
    my_solar_cell = SolarCell([Layer(width=si('50nm'), material=GaAs)] +
                              [Layer(width=si('100nm'), material=Ag_mat)])
    solar_cell_solver(my_solar_cell, 'optics', opts)
    GaAs_positions = np.linspace(
        my_solar_cell[0].offset,
        my_solar_cell[0].offset + my_solar_cell[0].width, 1000)
    Ag_positions = np.linspace(
        my_solar_cell[1].offset,
        my_solar_cell[1].offset + my_solar_cell[1].width, 1000)
    GaAs_abs = np.trapz(my_solar_cell[0].diff_absorption(GaAs_positions),
                        GaAs_positions)
    Ag_abs = np.trapz(my_solar_cell[1].diff_absorption(Ag_positions),
                      Ag_positions)
    plt.plot(wl * 1e9,
             GaAs_abs,
             color=colors[c],
             linestyle='-',
             label=names[c])
Example #21
0
light_source = LightSource(
    source_type="standard",
    version="AM1.5g",
    x=wl,
    output_units="photon_flux_per_m",
    concentration=1,
)

# The definitions are all done, so we just start solving the properties,
# starting with the QE. We calculate the QE curve under illumination
solar_cell_solver(
    my_solar_cell,
    "qe",
    user_options={
        "light_source": light_source,
        "wavelength": wl,
        "optics_method": "TMM",
    },
)

# And now, the IV curves under various concentration levels.
# NOTE: Due to the presence of QWs and the fact we calculate things a 19 different
# concentrations, this might take a while (~4 hours).
# Remove the QWs as indicated above to test the code much faster.

num_con = 19
con = np.logspace(0, 3, num_con)
vint = np.linspace(-3.5, 4, 600)
V = np.linspace(-3.5, 0, 300)
Example #22
0
                            A=1,
                            R_shunt=np.inf,
                            n=3.5)

    my_solar_cell = SolarCell([db_junction3, db_junction2, db_junction],
                              T=T,
                              R_series=0)

    solar_cell_solver(my_solar_cell,
                      'iv',
                      user_options={
                          'T_ambient': T,
                          'db_mode': 'boltzmann',
                          'voltages': V,
                          'light_iv': True,
                          'wavelength': wl,
                          'optics_method': 'BL',
                          'light_source': light_source,
                          'position': z,
                          'radiative_coupling': rad,
                          'mpp': True,
                          'internal_voltages': Vin
                      })

    # This is the total junction IV
    ax[k].plot(my_solar_cell.iv['IV'][0],
               my_solar_cell.iv['IV'][1],
               marker='o',
               color=colours("Black"),
               ls='-',
               markerfacecolor='none',
Example #23
0
# setting kind = 'DA' in the Junction definition tells the electrical solver later to use the depletion approximation
optical_struct = SolarCell(ARC + top_junction + middle_junction + DBRa + DBRb +
                           DBRc + bottom_junction,
                           shading=0.05)

wl = np.linspace(250, 1700, 400) * 1e-9

options = State()
options.wavelength = wl
options.optics_method = 'TMM'
options.no_back_reflection = False
options.pol = 'p'
options.BL_correction = True
options.coherency_list = 111 * ['c']
options.theta = 30
solar_cell_solver(optical_struct, 'qe', options)

plt.figure()
plt.plot(
    wl * 1e9,
    optical_struct[0].layer_absorption + optical_struct[1].layer_absorption)
plt.plot(wl * 1e9, optical_struct[2].layer_absorption)
plt.plot(wl * 1e9, optical_struct[3].layer_absorption)
plt.plot(wl * 1e9, optical_struct[100].layer_absorption)
plt.plot(wl * 1e9, optical_struct.absorbed, '--')
plt.plot(wl * 1e9, optical_struct.transmitted, '--')
plt.plot(wl * 1e9, optical_struct.reflected, '--')
plt.legend(['ARC', 'top', 'middle', 'bottom', 'A', 'T', 'R'])
plt.ylim(0, 1)
plt.ylabel('Absorption/Transmission/Reflection')
plt.xlabel('Wavelength (nm)')
Example #24
0
                          T=T,
                          substrate=n_GaAs)

light_source = LightSource(source_type='standard',
                           version='AM1.5g',
                           x=wl,
                           output_units='photon_flux_per_m',
                           concentration=1)

# The definitions are all done, so we just start solving the properties, starting with the QE.

# We calculate the QE curve under illumination
solar_cell_solver(my_solar_cell,
                  'qe',
                  user_options={
                      'light_source': light_source,
                      'wavelength': wl,
                      'optics_method': 'TMM'
                  })

# And now, the IV curves under various concentration levels.
# NOTE: Due to the presence of QWs and the fact we calculate things a 19 different concentrations, this might take a
# while (~4 hours). Remove the QWs as indicated above to test the code much faster.

num_con = 3
con = np.logspace(0, 3, num_con)
vint = np.linspace(-3.5, 4, 600)
V = np.linspace(-3.5, 0, 300)

allI = []
isc = []
Example #25
0
          Air,
          geometry=[{
              'type': 'circle',
              'mat': TiO2,
              'center': (200, 200),
              'radius': 50
          }])
]

substrate = [Layer(width=si('50um'), material=GaAs)]
spacer = [Layer(width=si('25nm'), material=SiO2)]

solar_cell = SolarCell(spacer + GaAs_junction +
                       substrate)  # solar cell with SiO2 coating
opts.optics_method = 'TMM'
solar_cell_solver(solar_cell, 'qe', opts)
TMM_EQE = solar_cell[1].eqe(opts.wavelength)
opts.optics_method = 'BL'
solar_cell_solver(solar_cell, 'qe', opts)
BL_EQE = solar_cell[1].eqe(opts.wavelength)

solar_cell = SolarCell(spacer + GaAs_junction + DBR +
                       substrate)  # as above, with a DBR on the back
opts.optics_method = 'TMM'
solar_cell_solver(solar_cell, 'qe', opts)
TMM_EQE_DBR = solar_cell[1].eqe(opts.wavelength)

solar_cell = SolarCell(NP_layer + spacer + GaAs_junction + DBR + substrate)
# cell with TiO2 nanocylinder array on the front
opts.optics_method = 'RCWA'
opts.orders = 49  # number of diffraction orders to keep in the RCWA solver
color = ['b', 'g', 'r']
label = ['Top', 'Mid', 'Bot']

fig, ax = plt.subplots(1, 2, sharey='all', figsize=(7, 4.5))

for k, rad in enumerate([False, True]):

    # Input data for the 2D kind of junction
    db_junction = Junction(kind='2D', T=T, reff=0.3, jref=300, Eg=0.66, A=1, R_shunt=np.inf, n=3.5)
    db_junction2 = Junction(kind='2D', T=T, reff=1, jref=300, Eg=1.4, A=1, R_shunt=np.inf, n=3.5)
    db_junction3 = Junction(kind='2D', T=T, reff=1, jref=300, Eg=1.8, A=1, R_shunt=np.inf, n=3.5)

    my_solar_cell = SolarCell([db_junction3, db_junction2, db_junction], T=T, R_series=0)

    solar_cell_solver(my_solar_cell, 'iv',
                      user_options={'T_ambient': T, 'voltages': V, 'light_iv': True, 'wavelength': wl,
                                    'light_source': light_source, 'radiative_coupling': rad, 'mpp': True,
                                    'internal_voltages': Vin})

    # This is the total junction IV
    ax[k].plot(my_solar_cell.iv['IV'][0], my_solar_cell.iv['IV'][1], marker='o', color=colours("Black"), ls='-',
               markerfacecolor='none', markeredgecolor=colours("Black"))

    # This is the junciton IV when it is in the MJ device, including coupling if it is enabled. 
    for i, data in enumerate(my_solar_cell.iv['junction IV']):
        ax[k].plot(data[0], data[1], color[i] + '--', linewidth=2)

    # This is the junction IV as if it were an isolated device and therefore not affected by coupling or current limiting. 
    for i in range(my_solar_cell.junctions):
        ax[k].plot(V, -my_solar_cell(i).iv(V), color[i], linewidth=2, label=label[i])

    ax[k].set_ylim(0, 300)
Example #27
0
    ],
             sn=1,
             sp=1,
             kind='DA'),
])

total_width = ARC_width + n_material_width + p_material_width

options = default_options
options.optics_method = "TMM"
options.wavelength = wavelengths_optics
# options.position = np.linspace(0, total_width, 100000)
options.light_iv = True
V = np.linspace(0, 1.2, 200)

solar_cell_solver(solar_cell, 'iv', options)

reflected = solar_cell.reflected
absorbed_in_Si = solar_cell[1].layer_absorption

interp_ref = interp1d(options.wavelength, reflected)
interp_totalA = interp1d(options.wavelength, solar_cell[1].layer_absorption)

wavelengths_external = np.linspace(301, 1199, 800) * 1e-9

alpha = n_material.alpha(wavelengths_external)
A_layer = interp_totalA(wavelengths_external)

junction_width = n_material_width + p_material_width

Example #28
0
def run_solar_cell_model(task, model):
    """

    :param model:
    :return: a Solar cell object
    """

    # First, we take care of the options
    # ----------------------------------
    options = copy.copy(model['Global'])
    options.update(model['Electrical'])
    options.update(model['Optical'])
    T = float(options['T'])

    # We have to validate the options and check they have the correct format and type
    array_based_options = ['voltages', 'internal_voltages', 'position', 'wavelength']
    float_options = ['T', 'T_ambient']
    bool_options = ['mpp', 'light_iv', 'radiative_coupling']

    try:
        for p in options:
            # For the options that should be arrays, we create the arrays. The wavelength need ot be converted to meters
            if p in array_based_options:
                c = options[p].split(', ')
                ini = float(c[0])
                end = float(c[1])
                num = int(c[2])
                options[p] = np.linspace(ini, end, num) * 1e-9 ** (p == 'wavelength')

            # For the options that need to be floats
            elif p in float_options:
                options[p] = float(options[p])

            elif p in bool_options:
                options[p] = options[p].lower() in ['true', 'yes', 't', 1]

    except Exception as err:
        print('ERROR parsing the solver options: Option format not recognised')
        print(err)
        raise

    # Now we create the layers and junctions to the solar cell object
    # ---------------------------------------------------------------
    sc_data = model['Solar cell']
    all_layers = []
    all_materials = []

    for i in sc_data['structure']:
        current_element = sc_data[i[0]]

        # First the individual layers
        if 'Layer' in current_element['type']:
            layer_properties = {}
            width = current_element['width'] * 1e-9

            # Set the composition and get the properties, converting them to the correct units
            for key in current_element['options']:
                if key in ['element', 'x']:
                    layer_properties[current_element['options']['element']] = current_element['options']['x']
                else:
                    layer_properties[key] = current_element['options'][key] * conversion[key]

            all_materials.append(material(current_element['material'])(T=T, **layer_properties))

            all_layers.append(Layer(width, all_materials[-1], role=current_element['name']))
            continue

        # Unless it is an individual layer, we have junctions
        properties = {}
        for p in properties_junctions[current_element['type']]:
            properties[p] = default_junction_properties[p]

        properties.update(**current_element['options'])
        kind = current_element['type'].split('-')[-1]
        if 'TJ' in current_element['type']:
            new_junction = TunnelJunction(name=current_element['name'], kind=kind, T=T, **properties)
        else:
            new_junction = Junction(name=current_element['name'], kind=kind, T=T, **properties)

        # Now we add the layers, if any
        for l in i[1:]:
            current_child = sc_data[l]

            width = current_child['width'] * 1e-9
            layer_properties = {}

            # Set the composition and get the properties, converting them to the correct units
            for key in current_child['options']:
                if key in ['element', 'x']:
                    layer_properties[current_child['options']['element']] = current_child['options']['x']
                else:
                    layer_properties[key] = current_child['options'][key] * conversion[key]

            all_materials.append(material(current_child['material'])(T=T, **layer_properties))
            new_junction.append(Layer(width, all_materials[-1], role=current_child['name']))

        all_layers.append(new_junction)

    # Now we have to create the solar cell
    # ------------------------------------
    reflectivity = create_reflectivity(sc_data['reflectivity']) if sc_data['reflectivity'] != '' else None

    try:
        substrate = material(sc_data['substrate'])(T=T, **{sc_data['element']: sc_data['composition']})
    except KeyError:
        substrate = material(sc_data['substrate'])(T=T)

    sc = SolarCell(layers=all_layers, name=sc_data['name'], substrate=substrate, T=T, cell_area=sc_data['size'],
                   shading=sc_data['shading'], R_series=sc_data['r_series'], reflectivity=reflectivity)

    # With all said and done, we can run the solver
    # ---------------------------------------------
    solar_cell_solver(sc, task, user_options=options)
    print('Done!')

    return sc
Example #29
0
def solve_quasi_3D(solar_cell,
                   injection,
                   contacts,
                   options=None,
                   Lx=10e-6,
                   Ly=10e-6,
                   h=2e-6,
                   R_back=1e-16,
                   R_contact=1e-16,
                   R_line=1e-16,
                   bias_start=0,
                   bias_end=1.8,
                   bias_step=0.01):
    """ Entry function for the quasi-3D solver

    :param solar_cell: A solar cell object
    :param injection: 2D array indicating the (optical) injection mask
    :param contacts: 2D array indicating the electrical contacts
    :param options: Options for the 1D solar cell solver
    :param Lx: Pixel size in the X direction
    :param Ly: Pixel size in the Y direction
    :param h: Height of the metal fingers
    :param R_back: Resistance back contact
    :param R_contact: Contact resistance
    :param R_line: Resistivity metal fingers
    :param bias_start: Initial voltage (V)
    :param bias_end: Final voltage (V)
    :param bias_step: Voltage step (V)
    :return: A tuple with:

        - V [steps + 1] : 1D Array with the external voltages
        - I [steps + 1] : 1D Array with the current at all external V
        - Vall [xnodes, ynodes, 2 * junctions, steps + 1] : 4D Array with the voltages in all nodes, at all external V
        - Vmet [xnodes, ynodes, steps + 1] : 3D Array with the voltages in the metal nodes, at all external V
    """
    # We first start by the solar cell as if it were a normal, isolated cell
    print("Solving 1D Solar Cell...")
    solar_cell_solver(solar_cell, 'iv', user_options=options)
    print("... Done!\n")

    # We don't care about this IV curve, in principle, but we care about some of the parameters calculated, like jsc,
    # j01 or j02 if calculated from detailed balance. We extract those parameters from the cell
    totaljuncs = solar_cell.junctions

    Isc_array = np.zeros(totaljuncs)
    I01_array = np.zeros(totaljuncs)
    n1_array = np.zeros(totaljuncs)
    I02_array = np.zeros(totaljuncs)
    n2_array = np.zeros(totaljuncs)
    Eg_array = np.zeros(totaljuncs)
    rsh_array = np.zeros(totaljuncs)
    rshTop_array = np.zeros(totaljuncs)
    rshBot_array = np.zeros(totaljuncs)
    rseries_array = np.ones(totaljuncs) * 1e-16

    for i in range(totaljuncs):

        n1_array[i] = solar_cell(i).n1 if hasattr(solar_cell(i), 'n1') else 1
        n2_array[i] = solar_cell(i).n2 if hasattr(solar_cell(i), 'n2') else 2
        rsh_array[i] = min(solar_cell(i).R_shunt, 1e16) if hasattr(
            solar_cell(i), 'R_shunt') else 1e16
        rshTop_array[i] = max(solar_cell(i).R_sheet_top, 1e-16) if hasattr(
            solar_cell(i), 'R_sheet_top') else 1e-16
        rshBot_array[i] = max(solar_cell(i).R_sheet_bot, 1e-16) if hasattr(
            solar_cell(i), 'R_sheet_bot') else 1e-16

        try:
            Isc_array[i] = solar_cell(i).jsc
            I01_array[i] = solar_cell(i).j01
            I02_array[i] = solar_cell(i).j02
            Eg_array[i] = solar_cell(i).Eg
        except AttributeError as err:
            raise AttributeError(
                'ERROR in quasi-3D solver: Junction is missing one essential argument. {}'
                .format(err))

    j = 0
    for i in solar_cell.tunnel_indices:
        rseries_array[j] = max(solar_cell[i].R_series, 1e-16) if hasattr(
            solar_cell[i], 'R_series') else 1e-16
        j += 1

    rseries_array[-1] = max(R_back, 1e-16)

    print("Solving quasi-3D Solar Cell...")
    V, I, Vall, Vmet = solve_circuit_quasi3D(
        bias_start, bias_end, bias_step, Isc_array, I01_array, I02_array,
        n1_array, n2_array, Eg_array, rsh_array, rseries_array, injection,
        contacts, rshTop_array, rshBot_array, R_line / h, R_contact, Lx, Ly)
    print("... Done!!")
    return V, I, Vall, Vmet
Example #30
0
                          T=T,
                          R_series=0,
                          substrate=substrate)

Vin = np.linspace(-2, 2.61, 201)
V = np.linspace(0, 2.6, 300)
wl = np.linspace(350, 1000, 301) * 1e-9
light_source = LightSource(source_type='standard',
                           version='AM1.5g',
                           x=wl,
                           output_units='photon_flux_per_m',
                           concentration=1)

if __name__ == '__main__':
    # We calculate the IV curve under illumination
    solar_cell_solver(my_solar_cell, 'equilibrium')
    # ,
    # user_options={'T_ambient': T, 'db_mode': 'boltzmann', 'voltages': V, 'light_iv': True,
    #               'wavelength': wl, 'optics_method': 'BL', 'mpp': True, 'internal_voltages': Vin,
    #               'light_source': light_source})

    # We can plot the electron and hole densities in equilibrium and at short circuit, both calculated automatically
    # before calculating the IV curve
    plt.figure(1)
    for j in my_solar_cell.junction_indices:
        zz = my_solar_cell[j].equilibrium_data.Properties['x'] + my_solar_cell[
            j].offset
        n = my_solar_cell[j].equilibrium_data.Properties['Nd']
        p = my_solar_cell[j].equilibrium_data.Properties['Na']
        plt.semilogy(zz, n, 'b')
        plt.semilogy(zz, p, 'r')