solphin 0.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- solphin-0.0.0/LICENSE +21 -0
- solphin-0.0.0/PKG-INFO +30 -0
- solphin-0.0.0/README.md +30 -0
- solphin-0.0.0/setup.cfg +4 -0
- solphin-0.0.0/setup.py +29 -0
- solphin-0.0.0/solphin/__init__.py +9 -0
- solphin-0.0.0/solphin/db_fom.py +304 -0
- solphin-0.0.0/solphin/db_plotting.py +81 -0
- solphin-0.0.0/solphin/final_results.py +73 -0
- solphin-0.0.0/solphin/optics.py +220 -0
- solphin-0.0.0/solphin/pv_fom.py +494 -0
- solphin-0.0.0/solphin/spectral.py +138 -0
- solphin-0.0.0/solphin/vasp_inputs.py +232 -0
- solphin-0.0.0/solphin/version.py +1 -0
- solphin-0.0.0/solphin.egg-info/PKG-INFO +30 -0
- solphin-0.0.0/solphin.egg-info/SOURCES.txt +17 -0
- solphin-0.0.0/solphin.egg-info/dependency_links.txt +1 -0
- solphin-0.0.0/solphin.egg-info/requires.txt +8 -0
- solphin-0.0.0/solphin.egg-info/top_level.txt +1 -0
solphin-0.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 ireaml
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
solphin-0.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: solphin
|
|
3
|
+
Version: 0.0.0
|
|
4
|
+
Summary: Figure of Merit for Photovoltaics
|
|
5
|
+
Home-page: https://github.com/SMTG-Bham/PV-FoM
|
|
6
|
+
Author: Philippa U Cox, Peter P Russell
|
|
7
|
+
Author-email: puc369@student.bham.ac.uk, ppr466@student.bham.ac.uk
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Development Status :: 1 - Planning
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: numpy
|
|
16
|
+
Requires-Dist: scipy
|
|
17
|
+
Requires-Dist: matplotlib>=3.9.4
|
|
18
|
+
Requires-Dist: pymatgen>=2024.8.9
|
|
19
|
+
Requires-Dist: mpmath
|
|
20
|
+
Requires-Dist: pathlib
|
|
21
|
+
Requires-Dist: typing_extensions
|
|
22
|
+
Requires-Dist: monty
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: author-email
|
|
25
|
+
Dynamic: classifier
|
|
26
|
+
Dynamic: home-page
|
|
27
|
+
Dynamic: license
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
Dynamic: requires-dist
|
|
30
|
+
Dynamic: summary
|
solphin-0.0.0/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# PV-FoM
|
|
2
|
+
|
|
3
|
+
**Please note that this code is still under development and not currently suitable for use**
|
|
4
|
+
|
|
5
|
+
`solphin` is a code developed to assist with the characterisation of novel photovoltaic materials with `VASP`. It combines detailed balance analysis with other tools such as the photovoltaic figure of merit proposed by A.Crovetto, Spectroscopic Limited Maximum Efficiency (SLME), Blank et al Maximum Efficiency and Optical tauc plots to provide a full picture of a materials theoretical photovoltaic efficiency.
|
|
6
|
+
|
|
7
|
+
*We request that any use of `solphin` in your work cites the code and theory papers*
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
`solphin` is currently only installable through the following method:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
git clone https://<PATOKEN>@github.com/SMTG-Bham/PV-FoM
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Navigate into `solphin` and run:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
pip install -e.
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
If using the `VASP` input file generation functionality, please ensure that your `VASP` pseudopotentials are added to your path through the use of a `pymatgen` configuration file `$HOME/.pmgrc.yaml`. The file should contain:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
PMG_VASP_PSP_DIR: <Path to VASP pseudopotential top directory>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
solphin-0.0.0/setup.cfg
ADDED
solphin-0.0.0/setup.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name='solphin',
|
|
5
|
+
version='0.0.0',
|
|
6
|
+
description='Figure of Merit for Photovoltaics',
|
|
7
|
+
url='https://github.com/SMTG-Bham/PV-FoM',
|
|
8
|
+
author='Philippa U Cox, Peter P Russell',
|
|
9
|
+
author_email='puc369@student.bham.ac.uk, ppr466@student.bham.ac.uk',
|
|
10
|
+
license='MIT',
|
|
11
|
+
packages=['solphin'],
|
|
12
|
+
install_requires=['numpy',
|
|
13
|
+
'scipy',
|
|
14
|
+
'matplotlib>=3.9.4',
|
|
15
|
+
'pymatgen>=2024.8.9',
|
|
16
|
+
'mpmath',
|
|
17
|
+
'pathlib',
|
|
18
|
+
'typing_extensions',
|
|
19
|
+
'monty'
|
|
20
|
+
],
|
|
21
|
+
|
|
22
|
+
classifiers=[
|
|
23
|
+
'Development Status :: 1 - Planning',
|
|
24
|
+
'Intended Audience :: Science/Research',
|
|
25
|
+
'License :: OSI Approved :: MIT License',
|
|
26
|
+
'Operating System :: POSIX :: Linux',
|
|
27
|
+
'Programming Language :: Python :: 3.9',
|
|
28
|
+
],
|
|
29
|
+
)
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import scipy.constants as sc
|
|
2
|
+
import numpy as np
|
|
3
|
+
import logging
|
|
4
|
+
from importlib.resources import files
|
|
5
|
+
|
|
6
|
+
logging.basicConfig(level=logging.INFO)
|
|
7
|
+
|
|
8
|
+
''' This section details the calculation of the detailed balance limit efficiency and associated values.'''
|
|
9
|
+
|
|
10
|
+
h = sc.h # Planck's constant (J·s)
|
|
11
|
+
c = sc.c # Speed of light (m/s)
|
|
12
|
+
k = sc.k # Boltzmann constant (J/K)
|
|
13
|
+
q = sc.e # Elementary charge (Coulombs)
|
|
14
|
+
|
|
15
|
+
# Convert the spectrum to the useful units - taken from https://github.com/kaklin/sq-limit?tab=readme-ov-file
|
|
16
|
+
|
|
17
|
+
def load_spectrum(spectrum_type):
|
|
18
|
+
|
|
19
|
+
if spectrum_type == "AM1.5":
|
|
20
|
+
filename = 'ASTMG173.csv'
|
|
21
|
+
|
|
22
|
+
elif spectrum_type == "Fluorescent":
|
|
23
|
+
filename = 'fluorescent.csv'
|
|
24
|
+
|
|
25
|
+
elif spectrum_type == "Blue LED":
|
|
26
|
+
filename = 'led_blue.csv'
|
|
27
|
+
|
|
28
|
+
elif spectrum_type == "Green LED":
|
|
29
|
+
filename = 'led_green.csv'
|
|
30
|
+
|
|
31
|
+
elif spectrum_type == "Red LED":
|
|
32
|
+
filename = 'led_red.csv'
|
|
33
|
+
|
|
34
|
+
elif spectrum_type == "White LED":
|
|
35
|
+
filename = 'led_white.csv'
|
|
36
|
+
|
|
37
|
+
elif spectrum_type == "IR LED":
|
|
38
|
+
filename = 'led_ir.csv'
|
|
39
|
+
|
|
40
|
+
elif spectrum_type == "Photopic":
|
|
41
|
+
filename = 'photopic.csv'
|
|
42
|
+
|
|
43
|
+
else:
|
|
44
|
+
print("Unrecognisable spectrum selected")
|
|
45
|
+
print("Options: AM1.5, Fluorescent, Blue LED, Green LED, Red LED, White LED, IR LED, Photopic")
|
|
46
|
+
print("reverting to AM1.5")
|
|
47
|
+
|
|
48
|
+
filename = 'ASTMG173.csv'
|
|
49
|
+
|
|
50
|
+
csv_path = files("placeholder.resources") / f"{filename}"
|
|
51
|
+
|
|
52
|
+
with csv_path.open("r", encoding="utf-8") as f:
|
|
53
|
+
spectrum = np.loadtxt(f, delimiter=",", skiprows=1)
|
|
54
|
+
|
|
55
|
+
return spectrum
|
|
56
|
+
|
|
57
|
+
def convert_spectrum(spectrum):
|
|
58
|
+
|
|
59
|
+
"""
|
|
60
|
+
Converts the input spectrum from standard format to the required units for this code.
|
|
61
|
+
|
|
62
|
+
Parameters:
|
|
63
|
+
spectrum(numpy.ndarray): Input spectrum loaded from a csv file with numpy.loadtxt.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
photon_spectrum(numpy.ndarray): Output spectrum as numpy ndarray.
|
|
67
|
+
|
|
68
|
+
Spectrum input:
|
|
69
|
+
y: Irradiance (W/m2/nm)
|
|
70
|
+
x: Wavelength (nm)
|
|
71
|
+
Converted output:
|
|
72
|
+
y: Number of photons (Np/m2/s/dE)
|
|
73
|
+
x: Energy (eV)
|
|
74
|
+
"""
|
|
75
|
+
converted = np.copy(spectrum)
|
|
76
|
+
converted[:, 0] = converted[:, 0] * 1e-9 # wavelength to m
|
|
77
|
+
converted[:, 1] = converted[:, 1] / 1e-9 # irradiance to W/m2/m (from W/m2/nm)
|
|
78
|
+
|
|
79
|
+
E = h * c / converted[:, 0]
|
|
80
|
+
d_lambda_d_E = h * c / E**2
|
|
81
|
+
converted[:, 1] = converted[:, 1] * d_lambda_d_E * q / E
|
|
82
|
+
converted[:, 0] = E / q
|
|
83
|
+
|
|
84
|
+
return converted
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def photons_above_bandgap(E_gap, photon_spectrum):
|
|
88
|
+
"""Counts number of photons above given bandgap.
|
|
89
|
+
|
|
90
|
+
Parameters:
|
|
91
|
+
E_gap(float): Optical Band Gap in eV
|
|
92
|
+
photon_spectrum(numpy.ndarray): Output spectrum as numpy ndarray.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
(float): Integration of the spectrum for the number of photons above the bandgap.
|
|
96
|
+
"""
|
|
97
|
+
indexes = np.where(photon_spectrum[:, 0] > E_gap)
|
|
98
|
+
y = photon_spectrum[indexes, 1][0]
|
|
99
|
+
x = photon_spectrum[indexes, 0][0]
|
|
100
|
+
return np.trapz(y[::-1], x[::-1])
|
|
101
|
+
|
|
102
|
+
def rr0(E_gap, photon_spectrum, Tcell):
|
|
103
|
+
'''
|
|
104
|
+
Calculates the radiative recombination rate at 0 Quasi-Fermi Level splitting.
|
|
105
|
+
|
|
106
|
+
Parameters:
|
|
107
|
+
E_gap(float): Optical Band Gap in eV
|
|
108
|
+
photon_spectrum(numpy.ndarray): Output spectrum as numpy ndarray.
|
|
109
|
+
Tcell(float): Operating temperature of the cell in K
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Radiative recomination rate(float) in cm⁻³s⁻¹
|
|
113
|
+
|
|
114
|
+
'''
|
|
115
|
+
k_eV = k / q
|
|
116
|
+
h_eV = h / q
|
|
117
|
+
const = (2 * np.pi) / (c**2 * h_eV**3)
|
|
118
|
+
|
|
119
|
+
k_eV = k / q
|
|
120
|
+
E = photon_spectrum[::-1, ] # in increasing order of bandgap energy
|
|
121
|
+
egap_index = np.where(E[:, 0] >= E_gap)
|
|
122
|
+
numerator = E[:, 0]**2
|
|
123
|
+
exponential_in = E[:, 0] / (k_eV * Tcell)
|
|
124
|
+
denominator = np.exp(exponential_in) - 1
|
|
125
|
+
integrand = numerator / denominator
|
|
126
|
+
|
|
127
|
+
integral = np.trapz(integrand[egap_index], E[egap_index, 0])
|
|
128
|
+
|
|
129
|
+
result = const * integral
|
|
130
|
+
return result[0]
|
|
131
|
+
|
|
132
|
+
def recomb_rate(E_gap, photon_spectrum, voltage, Tcell):
|
|
133
|
+
'''
|
|
134
|
+
Calculates the radiative recombination rate.
|
|
135
|
+
|
|
136
|
+
Parameters:
|
|
137
|
+
E_gap(float): Optical Band Gap in eV
|
|
138
|
+
photon_spectrum(numpy.ndarray): Output spectrum as numpy ndarray.
|
|
139
|
+
voltage(float): Open circuit voltage in V
|
|
140
|
+
Tcell(float): Operating temperature of the cell in K
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
Radiative recomination rate(float) in cm⁻³s⁻¹
|
|
144
|
+
|
|
145
|
+
'''
|
|
146
|
+
|
|
147
|
+
print ('recomb rate')
|
|
148
|
+
return q * rr0(E_gap, photon_spectrum) * np.exp(q * voltage / (k * Tcell))
|
|
149
|
+
|
|
150
|
+
def current_density(E_gap, photon_spectrum, voltage, Tcell):
|
|
151
|
+
'''
|
|
152
|
+
Calculates the current density.
|
|
153
|
+
|
|
154
|
+
Parameters:
|
|
155
|
+
E_gap(float): Optical Band Gap in eV
|
|
156
|
+
photon_spectrum(numpy.ndarray): Output spectrum as numpy ndarray.
|
|
157
|
+
voltage(float): Open circuit voltage in V
|
|
158
|
+
Tcell(float): Operating temperature of the cell in K
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
Current density (float): Current that flows across a cross sectional area in C cm⁻³s⁻¹.
|
|
162
|
+
|
|
163
|
+
'''
|
|
164
|
+
|
|
165
|
+
return q * (photons_above_bandgap(E_gap, photon_spectrum) - rr0(E_gap, photon_spectrum, Tcell) * np.exp(q * voltage / (k * Tcell)))
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def jsc(E_gap, photon_spectrum, Tcell):
|
|
169
|
+
|
|
170
|
+
'''
|
|
171
|
+
Calculates the current density.
|
|
172
|
+
|
|
173
|
+
Parameters:
|
|
174
|
+
E_gap(float): Optical Band Gap in eV
|
|
175
|
+
photon_spectrum(numpy.ndarray): Output spectrum as numpy ndarray.
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
Short circuit current density (float): Current that flows across a cross sectional area at 0 applied voltage in C cm⁻³s⁻¹.
|
|
179
|
+
|
|
180
|
+
'''
|
|
181
|
+
|
|
182
|
+
return current_density(E_gap, photon_spectrum, 0, Tcell)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def voc(E_gap, photon_spectrum, Tcell):
|
|
186
|
+
'''
|
|
187
|
+
Calculates the open circuit voltage.
|
|
188
|
+
|
|
189
|
+
Parameters:
|
|
190
|
+
E_gap(float): Optical Band Gap in eV
|
|
191
|
+
photon_spectrum(numpy.ndarray): Output spectrum as numpy ndarray.
|
|
192
|
+
Tcell(float): Operating temperature of the cell in K
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
Open circuit voltage (float): Maximum voltage across a solar cell with no current flow in V.
|
|
196
|
+
|
|
197
|
+
'''
|
|
198
|
+
|
|
199
|
+
# print 'voc'
|
|
200
|
+
return (k * Tcell / q) * np.log(photons_above_bandgap(E_gap, photon_spectrum) / rr0(E_gap, photon_spectrum, Tcell))
|
|
201
|
+
|
|
202
|
+
def v_at_mpp(E_gap, photon_spectrum):
|
|
203
|
+
|
|
204
|
+
'''
|
|
205
|
+
Calculates the voltage at maximum power point (mpp) of a solar cell.
|
|
206
|
+
|
|
207
|
+
Parameters:
|
|
208
|
+
E_gap(float): Optical Band Gap in eV
|
|
209
|
+
photon_spectrum(numpy.ndarray): Output spectrum as numpy ndarray.
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
Voltage at MPP (float): Voltage across a solar cell at the maximum power point in V.
|
|
213
|
+
|
|
214
|
+
'''
|
|
215
|
+
|
|
216
|
+
v_open = voc(E_gap, photon_spectrum)
|
|
217
|
+
# print v_open
|
|
218
|
+
v = np.linspace(0, v_open)
|
|
219
|
+
index = np.where(v * current_density(E_gap, photon_spectrum, v)==max(v * current_density(E_gap, photon_spectrum, v)))
|
|
220
|
+
return v[index][0]
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def j_at_mpp(E_gap, photon_spectrum):
|
|
224
|
+
|
|
225
|
+
'''
|
|
226
|
+
Calculates the current at maximum power point (mpp) of a solar cell.
|
|
227
|
+
|
|
228
|
+
Parameters:
|
|
229
|
+
E_gap(float): Optical Band Gap in eV
|
|
230
|
+
photon_spectrum(numpy.ndarray): Output spectrum as numpy ndarray.
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
Current at MPP (float): Current across a solar cell at the maximum power point.
|
|
234
|
+
|
|
235
|
+
'''
|
|
236
|
+
|
|
237
|
+
return max_power(E_gap, photon_spectrum) / v_at_mpp(E_gap, photon_spectrum)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def max_power(E_gap, photon_spectrum, Tcell):
|
|
241
|
+
|
|
242
|
+
'''
|
|
243
|
+
Calculates the maximum power of a solar cell.
|
|
244
|
+
|
|
245
|
+
Parameters:
|
|
246
|
+
E_gap(float): Optical Band Gap in eV
|
|
247
|
+
photon_spectrum(numpy.ndarray): Output spectrum as numpy ndarray.
|
|
248
|
+
Tcell(float): Operating temperature of the cell in K
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
Maximum power (float): Maximum power of the solar cell in V C cm⁻³ s⁻¹.
|
|
252
|
+
|
|
253
|
+
'''
|
|
254
|
+
|
|
255
|
+
v_open = voc(E_gap, photon_spectrum, Tcell)
|
|
256
|
+
v = np.linspace(0, v_open)
|
|
257
|
+
index = np.where(v * current_density(E_gap, photon_spectrum, v, Tcell)==max(v * current_density(E_gap, photon_spectrum, v, Tcell)))
|
|
258
|
+
return max(v * current_density(E_gap, photon_spectrum, v, Tcell))
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def max_eff(E_gap, photon_spectrum, Tcell):
|
|
262
|
+
|
|
263
|
+
'''
|
|
264
|
+
Calculates the maximum efficiency of a solar cell.
|
|
265
|
+
|
|
266
|
+
Parameters:
|
|
267
|
+
E_gap(float): Optical Band Gap in eV
|
|
268
|
+
photon_spectrum(numpy.ndarray): Output spectrum as numpy ndarray.
|
|
269
|
+
Tcell(float): Operating temperature of the cell in K
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
Maximum efficiency (float): Maximum effeciency of the solar cell relative to the total irradiance in %.
|
|
273
|
+
'''
|
|
274
|
+
|
|
275
|
+
photon_spectrum_1 = photon_spectrum[::-1, 1]
|
|
276
|
+
photon_spectrum_0 = photon_spectrum[::-1, 0]
|
|
277
|
+
|
|
278
|
+
irradiance = np.trapz(photon_spectrum_1 * q * photon_spectrum_0, photon_spectrum_0)
|
|
279
|
+
return max_power(E_gap, photon_spectrum, Tcell) / irradiance
|
|
280
|
+
|
|
281
|
+
def FillFactor(E_gap, photon_spectrum, Tcell):
|
|
282
|
+
|
|
283
|
+
'''
|
|
284
|
+
Calculates the fill factor of a solar cell.
|
|
285
|
+
|
|
286
|
+
Parameters:
|
|
287
|
+
E_gap(float): Optical Band Gap in eV
|
|
288
|
+
photon_spectrum(numpy.ndarray): Output spectrum as numpy ndarray.
|
|
289
|
+
Tcell(float): Operating temperature of the cell in K
|
|
290
|
+
|
|
291
|
+
Returns:
|
|
292
|
+
fill_factor (float): The fill factor of a solar cell.
|
|
293
|
+
'''
|
|
294
|
+
|
|
295
|
+
j_sc = jsc(E_gap, photon_spectrum)
|
|
296
|
+
v_oc = voc(E_gap, photon_spectrum, Tcell)
|
|
297
|
+
v_mpp = v_at_mpp(E_gap, photon_spectrum)
|
|
298
|
+
j_mpp = j_at_mpp(E_gap, photon_spectrum)
|
|
299
|
+
|
|
300
|
+
fill_factor = (j_mpp * v_mpp) / (j_sc, v_oc)
|
|
301
|
+
|
|
302
|
+
return fill_factor
|
|
303
|
+
|
|
304
|
+
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import solphin.db_fom as db_fom
|
|
2
|
+
import numpy as np
|
|
3
|
+
import matplotlib.pyplot as plt
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
logging.basicConfig(level=logging.INFO)
|
|
8
|
+
|
|
9
|
+
def photons_above_bandgap_plot(spectrum, Egap):
|
|
10
|
+
"""Plot of photons above bandgap as a function of bandgap"""
|
|
11
|
+
a = np.copy(spectrum)
|
|
12
|
+
for row in a:
|
|
13
|
+
# print row
|
|
14
|
+
row[1] = db_fom.photons_above_bandgap(row[0], spectrum)
|
|
15
|
+
plt.plot(a[:, 0], a[:, 1], color='#231123')
|
|
16
|
+
|
|
17
|
+
p_above_1_1 = db_fom.photons_above_bandgap(Egap, spectrum)
|
|
18
|
+
plt.plot([Egap], [p_above_1_1], 'ro', color='#FF6666')
|
|
19
|
+
plt.text(Egap+0.05, p_above_1_1, '{}eV, {:.4}'.format(Egap, p_above_1_1))
|
|
20
|
+
|
|
21
|
+
plt.xlabel('$E_{gap}$ (eV)')
|
|
22
|
+
plt.ylabel('# Photons $m^{-2}s^{-1}$')
|
|
23
|
+
plt.title('Number of above-bandgap \nphotons as a function of bandgap')
|
|
24
|
+
plt.show()
|
|
25
|
+
|
|
26
|
+
def iv_curve_plot(egap, spectrum, Tcell, power=False):
|
|
27
|
+
"""Plots the ideal IV curve, or the ideal power for a given material"""
|
|
28
|
+
v_open = db_fom.voc(egap, spectrum, Tcell)
|
|
29
|
+
v = np.linspace(0, v_open)
|
|
30
|
+
if power:
|
|
31
|
+
p = v * db_fom.current_density(egap, spectrum, v, Tcell)
|
|
32
|
+
plt.xlabel('Voltage (V)')
|
|
33
|
+
plt.ylabel('Power generated ($W$)')
|
|
34
|
+
plt.title('Power Curve')
|
|
35
|
+
plt.plot(v, p, color='#231123')
|
|
36
|
+
else:
|
|
37
|
+
i = db_fom.current_density(egap, spectrum, v, Tcell)
|
|
38
|
+
plt.xlabel('Voltage (V)')
|
|
39
|
+
plt.ylabel('Current density $J$ ($Am^{-2}$)')
|
|
40
|
+
plt.title('IV Curve')
|
|
41
|
+
plt.plot(v, i, color='#231123')
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def iv_curve_plot_2(egap, spectrum, Tcell, power=False):
|
|
45
|
+
"""Plots the ideal IV curve, and the ideal power for a given material"""
|
|
46
|
+
v_open = db_fom.voc(egap, spectrum, Tcell)
|
|
47
|
+
v = np.linspace(0, v_open)
|
|
48
|
+
|
|
49
|
+
fig, ax1 = plt.subplots()
|
|
50
|
+
p = v * db_fom.current_density(egap, spectrum, v, Tcell)
|
|
51
|
+
i = db_fom.current_density(egap, spectrum, v, Tcell)
|
|
52
|
+
|
|
53
|
+
ax1.plot(v, i, color='#231123')
|
|
54
|
+
ax1.set_xlabel('Voltage (V)')
|
|
55
|
+
ax1.set_ylabel('Current density $J$ ($Am^{-2}$)')
|
|
56
|
+
ax1.legend(['Current'], loc=2)
|
|
57
|
+
|
|
58
|
+
ax2 = ax1.twinx()
|
|
59
|
+
ax2.plot(v, p, color='#FF6666')
|
|
60
|
+
ax2.set_ylabel('Power generated ($W$)')
|
|
61
|
+
ax2.legend(['Power'], loc=3)
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def sq_limit_plot(spectrum, Egap, Tcell):
|
|
66
|
+
# Plot the famous SQ limit
|
|
67
|
+
a = np.copy(spectrum)
|
|
68
|
+
# Not for whole array hack to remove divide by 0 errors
|
|
69
|
+
for row in a[2:]:
|
|
70
|
+
# print row
|
|
71
|
+
row[1] = db_fom.max_eff(row[0], spectrum, Tcell)
|
|
72
|
+
# Not plotting whole array becase some bad values happen
|
|
73
|
+
plt.plot(a[2:, 0], a[2:, 1])
|
|
74
|
+
e_gap = Egap
|
|
75
|
+
p_above_1_1 = db_fom.max_eff(e_gap, spectrum, Tcell)
|
|
76
|
+
plt.plot([e_gap], [p_above_1_1], 'ro')
|
|
77
|
+
plt.text(e_gap+0.05, p_above_1_1, '{}eV, {:.4}'.format(e_gap, p_above_1_1))
|
|
78
|
+
|
|
79
|
+
plt.xlabel('$E_{gap}$ (eV)')
|
|
80
|
+
plt.ylabel('Max efficiency')
|
|
81
|
+
plt.title('SQ Limit')
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from solphin.pv_fom import Final_equation
|
|
2
|
+
from solphin.db_fom import max_eff
|
|
3
|
+
|
|
4
|
+
# Calculating equation 33 from the FOM paper
|
|
5
|
+
|
|
6
|
+
def Crovetto_efficiency(E_gap, photon_spectrum, alpha, tau, sigma, dos_mass, dop_density, epsilon, mu, Tcell):
|
|
7
|
+
|
|
8
|
+
''' Calculates the final value for the photovoltaic figure of merit from Crovetto 2024
|
|
9
|
+
|
|
10
|
+
Parameters:
|
|
11
|
+
E_gap(float): Optical Band Gap in eV
|
|
12
|
+
photon_spectrum(numpy.ndarrray): Converted input spectrum from DB_FOM.convert_spectrum y: Number of photons (Np/m2/s/dE) x: Energy (eV)
|
|
13
|
+
alpha(float): Spectral average of incident light in cm⁻¹
|
|
14
|
+
tau(float): Non-radiative recombination lifetime in s
|
|
15
|
+
sigma(float): Spectral dispersion of the absorption coefficient spectrum, unitless
|
|
16
|
+
dos_mass(float): Density of States effective mass in m₀
|
|
17
|
+
dop_density(float): Doping density in cm⁻³
|
|
18
|
+
epsilon(float): Static dielectric constant, unitless
|
|
19
|
+
mu(float): Charge carrier mobility in cm²V⁻¹s⁻¹
|
|
20
|
+
Tcell(float): Operating temperature of the cell in K
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
efficiency(float): Percentage photovoltaic figure of merit efficiency.
|
|
24
|
+
'''
|
|
25
|
+
|
|
26
|
+
PV_FOM = Final_equation(E_gap, alpha, tau, sigma, dos_mass, dop_density, epsilon, mu)
|
|
27
|
+
|
|
28
|
+
k_1 = 3.3e-1
|
|
29
|
+
k_2 = 9.06e-2
|
|
30
|
+
k_3 = 2.48e-3
|
|
31
|
+
|
|
32
|
+
FOM_Pv_235 = PV_FOM ** (-0.235)
|
|
33
|
+
FOM_Pv_869 = PV_FOM ** 0.869
|
|
34
|
+
FOM_Pv_362 = PV_FOM ** (-0.362)
|
|
35
|
+
|
|
36
|
+
fraction = (k_1 * FOM_Pv_235) / (1 + k_2 * FOM_Pv_869)
|
|
37
|
+
denom_bracket = 1 + (k_3 * FOM_Pv_362)
|
|
38
|
+
|
|
39
|
+
SQ_eff = max_eff(E_gap, photon_spectrum, Tcell)
|
|
40
|
+
SQ = SQ_eff * 100
|
|
41
|
+
|
|
42
|
+
efficiency = SQ / ((1 + fraction) * denom_bracket)
|
|
43
|
+
|
|
44
|
+
return efficiency
|
|
45
|
+
|
|
46
|
+
# Crovetto efficiency realtive to SQ limit
|
|
47
|
+
|
|
48
|
+
def SQ_relative_Crovetto_efficiency(E_gap, photon_spectrum, alpha, tau, sigma, dos_mass, dop_density, epsilon, mu, Tcell):
|
|
49
|
+
|
|
50
|
+
''' Calculates the final value for the photovoltaic figure of merit relative to the SQ limit from Crovetto 2024
|
|
51
|
+
|
|
52
|
+
Parameters:
|
|
53
|
+
E_gap(float): Optical Band Gap in eV
|
|
54
|
+
photon_spectrum(numpy.ndarrray): Converted input spectrum from DB_FOM.convert_spectrum y: Number of photons (Np/m2/s/dE) x: Energy (eV)
|
|
55
|
+
alpha(float): Spectral average of incident light in cm⁻¹
|
|
56
|
+
tau(float): Non-radiative recombination lifetime in s
|
|
57
|
+
sigma(float): Spectral dispersion of the absorption coefficient spectrum, unitless
|
|
58
|
+
dos_mass(float): Density of States effective mass in m₀
|
|
59
|
+
dop_density(float): Doping density in cm⁻³
|
|
60
|
+
epsilon(float): Static dielectric constant, unitless
|
|
61
|
+
mu(float): Charge carrier mobility in cm²V⁻¹s⁻¹
|
|
62
|
+
Tcell(float): Operating temperature of the cell in K
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
efficiency(float): Percentage photovoltaic figure of merit efficiency relative to the SQ limit.
|
|
66
|
+
'''
|
|
67
|
+
|
|
68
|
+
Crovetto_eff = Crovetto_efficiency(E_gap, photon_spectrum, alpha, tau, sigma, dos_mass, dop_density, epsilon, mu, Tcell)
|
|
69
|
+
SQ = max_eff(E_gap, photon_spectrum, Tcell)
|
|
70
|
+
|
|
71
|
+
SQ_relative = Crovetto_eff / SQ
|
|
72
|
+
|
|
73
|
+
return SQ_relative
|