Skip to content

Commit d61a134

Browse files
authored
Merge pull request #34 from opusonesolutions/type-hint
add type hinting
2 parents c888aba + b2a4de8 commit d61a134

File tree

6 files changed

+73
-45
lines changed

6 files changed

+73
-45
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.pytest_cache/
2+
*/__pycache__/

.travis.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ jobs:
66
- python: 3.6
77
- python: 3.7
88
dist: xenial
9+
- python: 3.8
10+
dist: xenial
911
- stage: deploy
1012
install: skip
1113
script: true
@@ -26,5 +28,5 @@ install:
2628
- pip install flake8 coveralls
2729
script:
2830
- flake8
29-
- pytest --cov-report term-missing --cov=carsons tests/
31+
- pytest --mypy --cov-report term-missing --cov=carsons tests/
3032
after_success: coveralls

carsons/carsons.py

Lines changed: 48 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
11
from collections import defaultdict
22
from itertools import islice
3+
from typing import Dict, Iterable, Iterator, Tuple
34

45
from numpy import arctan, cos, log, sin, sqrt, zeros
6+
from numpy import ndarray
57
from numpy import pi as π
68
from numpy.linalg import inv
79

810

9-
def convert_geometric_model(geometric_model):
11+
def convert_geometric_model(geometric_model) -> ndarray:
1012
carsons_model = CarsonsEquations(geometric_model)
1113

1214
z_primitive = carsons_model.build_z_primitive()
1315
z_abc = perform_kron_reduction(z_primitive)
1416
return z_abc
1517

1618

17-
def calculate_impedance(model):
19+
def calculate_impedance(model) -> ndarray:
1820
z_primitive = model.build_z_primitive()
1921
z_abc = perform_kron_reduction(z_primitive)
2022
return z_abc
2123

2224

23-
def perform_kron_reduction(z_primitive):
25+
def perform_kron_reduction(z_primitive: ndarray) -> ndarray:
2426
""" Reduces the primitive impedance matrix to an equivalent impedance
2527
matrix.
2628
@@ -66,38 +68,36 @@ class CarsonsEquations():
6668
μ = 4 * π * 1e-7 # permeability, Henry / meter
6769

6870
def __init__(self, model):
69-
self.phases = model.phases
70-
self.phase_positions = model.wire_positions
71-
self.gmr = model.geometric_mean_radius
72-
self.r = model.resistance
71+
self.phases: Iterable[str] = model.phases
72+
self.phase_positions: Dict[str, Tuple[float, float]] = \
73+
model.wire_positions
74+
self.gmr: Dict[str, float] = model.geometric_mean_radius
75+
self.r: Dict[str, float] = model.resistance
7376

7477
self.ƒ = getattr(model, 'frequency', 60)
7578
self.ω = 2.0 * π * self.ƒ # angular frequency radians / second
7679

77-
def build_z_primitive(self):
78-
abc_conductors = [
79-
ph if ph in self.phases
80-
else None for ph in ("A", "B", "C")
81-
]
80+
def build_z_primitive(self) -> ndarray:
8281
neutral_conductors = sorted([
8382
ph for ph in self.phases
8483
if ph.startswith("N")
8584
])
86-
conductors = abc_conductors + neutral_conductors
85+
conductors = ["A", "B", "C"] + neutral_conductors
8786

8887
dimension = len(conductors)
8988
z_primitive = zeros(shape=(dimension, dimension), dtype=complex)
9089

9190
for index_i, phase_i in enumerate(conductors):
9291
for index_j, phase_j in enumerate(conductors):
93-
if phase_i is not None and phase_j is not None:
94-
R = self.compute_R(phase_i, phase_j)
95-
X = self.compute_X(phase_i, phase_j)
96-
z_primitive[index_i, index_j] = complex(R, X)
92+
if phase_i not in self.phases or phase_j not in self.phases:
93+
continue
94+
R = self.compute_R(phase_i, phase_j)
95+
X = self.compute_X(phase_i, phase_j)
96+
z_primitive[index_i, index_j] = complex(R, X)
9797

9898
return z_primitive
9999

100-
def compute_R(self, i, j):
100+
def compute_R(self, i, j) -> float:
101101
rᵢ = self.r[i]
102102
ΔR = self.μ * self.ω / π * self.compute_P(i, j)
103103

@@ -106,7 +106,7 @@ def compute_R(self, i, j):
106106
else:
107107
return ΔR
108108

109-
def compute_X(self, i, j):
109+
def compute_X(self, i, j) -> float:
110110
Qᵢⱼ = self.compute_Q(i, j)
111111
ΔX = self.μ * self.ω / π * Qᵢⱼ
112112

@@ -124,11 +124,11 @@ def compute_X(self, i, j):
124124

125125
return X_o + ΔX
126126

127-
def compute_P(self, i, j, number_of_terms=1):
127+
def compute_P(self, i, j, number_of_terms=1) -> float:
128128
terms = islice(self.compute_P_terms(i, j), number_of_terms)
129129
return sum(terms)
130130

131-
def compute_P_terms(self, i, j):
131+
def compute_P_terms(self, i, j) -> Iterator[float]:
132132
yield π / 8.0
133133

134134
kᵢⱼ = self.compute_k(i, j)
@@ -140,11 +140,11 @@ def compute_P_terms(self, i, j):
140140
yield kᵢⱼ ** 3 / (45 * sqrt(2)) * cos(3 * θᵢⱼ)
141141
yield -π * kᵢⱼ ** 4 * cos(4 * θᵢⱼ) / 1536
142142

143-
def compute_Q(self, i, j, number_of_terms=2):
143+
def compute_Q(self, i, j, number_of_terms=2) -> float:
144144
terms = islice(self.compute_Q_terms(i, j), number_of_terms)
145145
return sum(terms)
146146

147-
def compute_Q_terms(self, i, j):
147+
def compute_Q_terms(self, i, j) -> Iterator[float]:
148148
yield -0.0386
149149

150150
kᵢⱼ = self.compute_k(i, j)
@@ -157,30 +157,31 @@ def compute_Q_terms(self, i, j):
157157
yield -kᵢⱼ ** 4 / 384 * θᵢⱼ * sin(4 * θᵢⱼ)
158158
yield -kᵢⱼ ** 4 / 384 * cos(4 * θᵢⱼ) * (log(2 / kᵢⱼ) + 1.0895)
159159

160-
def compute_k(self, i, j):
160+
def compute_k(self, i, j) -> float:
161161
Dᵢⱼ = self.compute_D(i, j)
162162
return Dᵢⱼ * sqrt(self.ω * self.μ / self.ρ)
163163

164-
def compute_θ(self, i, j):
164+
def compute_θ(self, i, j) -> float:
165165
xᵢ, _ = self.phase_positions[i]
166166
xⱼ, _ = self.phase_positions[j]
167167
xᵢⱼ = abs(xⱼ - xᵢ)
168168
hᵢ, hⱼ = self.get_h(i), self.get_h(j)
169169

170170
return arctan(xᵢⱼ / (hᵢ + hⱼ))
171171

172-
def compute_d(self, i, j):
172+
def compute_d(self, i, j) -> float:
173173
return self.calculate_distance(
174174
self.phase_positions[i],
175-
self.phase_positions[j])
175+
self.phase_positions[j],
176+
)
176177

177-
def compute_D(self, i, j):
178+
def compute_D(self, i, j) -> float:
178179
xⱼ, yⱼ = self.phase_positions[j]
179180

180181
return self.calculate_distance(self.phase_positions[i], (xⱼ, -yⱼ))
181182

182183
@staticmethod
183-
def calculate_distance(positionᵢ, positionⱼ):
184+
def calculate_distance(positionᵢ, positionⱼ) -> float:
184185
xᵢ, yᵢ = positionᵢ
185186
xⱼ, yⱼ = positionⱼ
186187
return sqrt((xᵢ - xⱼ)**2 + (yᵢ - yⱼ)**2)
@@ -193,16 +194,21 @@ def get_h(self, i):
193194
class ConcentricNeutralCarsonsEquations(CarsonsEquations):
194195
def __init__(self, model, *args, **kwargs):
195196
super().__init__(model)
196-
self.neutral_strand_gmr = model.neutral_strand_gmr
197-
self.neutral_strand_count = defaultdict(
198-
lambda: None, model.neutral_strand_count)
199-
self.neutral_strand_resistance = model.neutral_strand_resistance
200-
self.radius = defaultdict(lambda: None, {
201-
phase: (diameter_over_neutral -
202-
model.neutral_strand_diameter[phase]) / 2
203-
for phase, diameter_over_neutral
204-
in model.diameter_over_neutral.items()
205-
})
197+
self.neutral_strand_gmr: Dict[str, float] = model.neutral_strand_gmr
198+
self.neutral_strand_count: Dict[str, float] = defaultdict(
199+
lambda: None,
200+
model.neutral_strand_count
201+
)
202+
self.neutral_strand_resistance: Dict[str, float] = \
203+
model.neutral_strand_resistance
204+
self.radius: Dict[str, float] = defaultdict(
205+
lambda: None, {
206+
phase: (diameter_over_neutral -
207+
model.neutral_strand_diameter[phase]) / 2
208+
for phase, diameter_over_neutral
209+
in model.diameter_over_neutral.items()
210+
}
211+
)
206212
self.phase_positions.update({
207213
f"N{phase}": self.phase_positions[phase]
208214
for phase in self.phase_positions.keys()
@@ -217,7 +223,7 @@ def __init__(self, model, *args, **kwargs):
217223
})
218224
return
219225

220-
def compute_d(self, i, j):
226+
def compute_d(self, i, j) -> float:
221227
I, J = set(i), set(j)
222228
r = self.radius[i] or self.radius[j]
223229

@@ -240,7 +246,7 @@ def compute_d(self, i, j):
240246
# Distance between two neutral/phase conductors
241247
return distance_ij
242248

243-
def compute_X(self, i, j):
249+
def compute_X(self, i, j) -> float:
244250
Q_first_term = super().compute_Q(i, j, 1)
245251

246252
# Simplify equations and don't compute Dᵢⱼ explicitly
@@ -254,7 +260,7 @@ def compute_X(self, i, j):
254260

255261
return (X_o + ΔX) * self.ω * self.μ / (2 * π)
256262

257-
def GMR_cn(self, phase):
263+
def GMR_cn(self, phase) -> float:
258264
GMR_s = self.neutral_strand_gmr[phase]
259265
k = self.neutral_strand_count[phase]
260266
R = self.radius[phase]

carsons/py.typed

Whitespace-only changes.

mypy.ini

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[mypy]
2+
python_version = 3.6
3+
4+
[mypy-numpy.*]
5+
ignore_missing_imports = True
6+
7+
[mypy-setuptools.*]
8+
ignore_missing_imports = True
9+
10+
[mypy-pytest.*,pint.*]
11+
ignore_missing_imports = True

setup.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ def readme():
1515
version=version,
1616
packages=["carsons"],
1717
package_data={
18-
'': ['VERSION']
18+
'': ['VERSION'],
19+
'carsons': ['py.typed'],
1920
},
2021
description="A python library computing carson's equations.",
2122
classifiers=[
@@ -38,7 +39,13 @@ def readme():
3839
install_requires=[
3940
'numpy>=1.13.1',
4041
],
42+
zip_safe=False,
4143
extras_require={
42-
"test": ["pytest>=3.6", "pytest-cov", "pint"],
44+
"test": [
45+
"pytest>=3.6",
46+
"pytest-cov",
47+
"pytest-mypy",
48+
"pint",
49+
],
4350
},
4451
)

0 commit comments

Comments
 (0)