/
test_mobility_parameters.py
170 lines (135 loc) · 5.52 KB
/
test_mobility_parameters.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
from pytest import raises, mark, approx
from pint import Quantity
from hypothesis import given, settings, Verbosity
import hypothesis.strategies as st
def test_mobility_low_field():
from solcore.parameter_sources.mobility_parameters import mobility_low_field
T = Quantity(298, "K")
N = Quantity(1e18, "1/cm**3")
mu_min = Quantity(500, "cm**2/V/s")
mu_max = Quantity(9200, "cm**2/V/s")
Nref = Quantity(6e16, "1/cm**3")
l = 0.394
t1 = 1.1
t2 = 3.0
out = mobility_low_field(T, N, mu_min, mu_max, Nref, l, t1, t2)
out_larger = mobility_low_field(T, N / 10, mu_min, mu_max, Nref, l, t1, t2)
assert out_larger > out
smallT = mobility_low_field(T * 0.01, N, mu_min, mu_max, Nref, l, t1, t2)
largeT = mobility_low_field(T * 100, N, mu_min, mu_max, Nref, l, t1, t2)
assert smallT < out
assert largeT < out
t1 = 2.1
smallT = mobility_low_field(T * 0.01, N, mu_min, mu_max, Nref, l, t1, t2)
largeT = mobility_low_field(T * 100, N, mu_min, mu_max, Nref, l, t1, t2)
assert out < smallT
assert largeT < out
class TestSotoodehMobilitySource:
def test_load_source(self):
from solcore.parameter_sources import SotoodehMobilitySource
sm = SotoodehMobilitySource.load_source()
assert sm == SotoodehMobilitySource()
assert len(sm.reference) > 0
assert len(sm._descriptions) > 0
assert len(sm._data) > 0
def test_materials(self):
from solcore.parameter_sources import SotoodehMobilitySource
sm = SotoodehMobilitySource()
assert sm.materials == tuple((m for m in sm._data if len(m) <= 4))
def test_parameters(self):
from solcore.parameter_sources import SotoodehMobilitySource
from solcore.parameter import ParameterError
sm = SotoodehMobilitySource()
msg = f"Material 'Dark matter' not in '{sm.name}' source."
with raises(ParameterError, match=msg):
sm.parameters("Dark matter")
assert sm.parameters(sm.materials[0]) == ("electron_mobility", "hole_mobility")
@mark.parametrize("carrier", ["electron", "hole"])
@mark.parametrize(
"kwargs",
[
{},
{"T": Quantity(298, "K")},
{"T": Quantity(298, "K"), "Nd": Quantity(1e18, "1/cm**3")},
{"T": Quantity(298, "K"), "Na": Quantity(1e18, "1/cm**3")},
],
)
def test_get_parameter(self, carrier, kwargs):
from solcore.parameter_sources import SotoodehMobilitySource
sm = SotoodehMobilitySource()
material = sm.materials[0]
required = {"electron": ("T", "Nd"), "hole": ("T", "Na")}[carrier]
if tuple(kwargs.keys()) != required:
msg = f"Missing at least one required parameter for carrier '{carrier}'"
with raises(KeyError, match=msg):
sm.get_parameter(material, f"{carrier}_mobility", **kwargs)
else:
out = sm.get_parameter(material, f"{carrier}_mobility", **kwargs)
assert out.d == sm._descriptions[f"{carrier}_mobility"]
assert out.r == (sm.name,)
assert out.u == "meter ** 2 / second / volt"
@mark.xfail(reason="Method not implemented, yet.")
def test__get_parameter_alloy(self):
assert False
@given(
egg=st.floats(0.2, 2),
egx=st.floats(0.2, 2),
egl=st.floats(0.2, 2),
mg=st.floats(0.001, 3),
mx=st.floats(0.001, 3),
ml=st.floats(0.001, 3),
T=st.floats(20, 500),
)
def test_fraction_electrons_direct_valley(egg, egx, egl, mg, mx, ml, T):
from solcore.parameter_sources.mobility_parameters import (
fraction_electrons_direct_valley,
)
egg = Quantity(egg, "eV")
egx = Quantity(egx, "eV")
egl = Quantity(egl, "eV")
mg = Quantity(mg)
mx = Quantity(mx)
ml = Quantity(ml)
T = Quantity(T, "K")
fraction = fraction_electrons_direct_valley(egg, egx, egl, mg, mx, ml, T)
assert 0 <= fraction <= 1
egg = 0.9 * egg
new_fraction = fraction_electrons_direct_valley(egg, egx, egl, mg, mx, ml, T)
assert fraction <= new_fraction
@given(
egx=st.floats(0.2, 2),
egl=st.floats(0.2, 2),
mx=st.floats(0.001, 3),
ml=st.floats(0.001, 3),
T=st.floats(20, 500),
)
def test_effective_indirect_mass(egx, egl, mx, ml, T):
from solcore.parameter_sources.mobility_parameters import effective_indirect_mass
egx = Quantity(egx, "eV")
egl = Quantity(egl, "eV")
mx = Quantity(mx)
ml = Quantity(ml)
T = Quantity(T, "K")
m = effective_indirect_mass(egx, egl, mx, ml, T)
assert abs(m - mx).m + abs(m - ml).m == approx(abs(mx - ml).m)
egl = egl / 2
new_m = effective_indirect_mass(egx, egl, mx, ml, T)
if not mx.m == approx(ml.m):
assert abs(m - ml) >= abs(new_m - ml)
else:
assert m.m == approx(new_m.m)
@given(e1=st.floats(4, 20), e2=st.floats(4, 20), x=st.floats(0, 1))
def test_interpolate_epsilon(e1, e2, x):
from solcore.parameter_sources.mobility_parameters import interpolate_epsilon
ratio1 = (e1 - 1) / (e1 + 2)
ratio2 = (e2 - 1) / (e2 + 2)
expected = x * ratio1 + (1 - x) * ratio2
eo = interpolate_epsilon(e1, e2, x)
actual = (eo - 1) / (eo + 2)
assert actual == approx(expected)
@given(n1=st.floats(1e12, 1e22), n2=st.floats(1e12, 1e22), x=st.floats(0, 1))
def test_interpolate_concentration(n1, n2, x):
from solcore.parameter_sources.mobility_parameters import interpolate_concentration
import numpy as np
expected = x * np.log10(n1) + (1.0 - x) * np.log10(n2)
assert np.log10(interpolate_concentration(n1, n2, x)) == approx(expected)