Skip to content

Commit

Permalink
Merge pull request #10 from opusonesolutions/support-multiple-neutrals
Browse files Browse the repository at this point in the history
Test support for multiple neutrals, get rid of dict of 'A' -> 'A'
  • Loading branch information
AnjoMan committed Jan 22, 2019
2 parents fc794ae + 2002da4 commit 6919cd5
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 33 deletions.
5 changes: 1 addition & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,7 @@ of the conductor for that phase.
'A' => (x, y) cross-sectional position of the conductor in meters
...
}
phases: {
'A', => 'A'
...
}
phases: {'A', ... }
# map of phases 'A', 'B', 'C' and 'N<>' which are described in the
# gmr, r and phase_positions attributes
Expand Down
14 changes: 8 additions & 6 deletions carsons/carsons.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def perform_kron_reduction(z_primitive):
[Ẑcn₁, Ẑcn₂]
Ẑna = [Ẑn₁a, Ẑn₁b, Ẑn₁c] Ẑnn = [Ẑn₁n₁, Ẑn₁n₂]
[Ẑn₂a, Ẑnb, Ẑnc] [Ẑn₂n₁, Ẑn₂n₂]
[Ẑn₂a, Ẑnb, Ẑnc] [Ẑn₂n₁, Ẑn₂n₂]
Definitions:
Ẑ ----- "primative" impedance value, i.e. one that does not factor
Expand Down Expand Up @@ -72,12 +72,14 @@ def __init__(self, model):
self.r = model.resistance

def build_z_primitive(self):

abc_conductors = [self.phases.get(ph, None) for ph in ['A', 'B', 'C']]
neutral_conductors = [
p for ph, p in self.phases.items()
if ph.startswith('N')
abc_conductors = [
ph if ph in self.phases
else None for ph in ("A", "B", "C")
]
neutral_conductors = sorted([
ph for ph in self.phases
if ph.startswith("N")
])
conductors = abc_conductors + neutral_conductors

dimension = len(conductors)
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@ def readme():
'numpy>=1.13.1',
],
extras_require={
"test": ["pytest", "pytest-cov"],
"test": ["pytest>=3.6", "pytest-cov"],
},
)
Empty file added tests/__init__.py
Empty file.
28 changes: 28 additions & 0 deletions tests/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
class LineModel:
def __init__(self, conductors):
self._resistance = {}
self._geometric_mean_radius = {}
self._wire_positions = {}
self._phases = {}

for phase, (r, gmr, (x, y)) in conductors.items():
self._resistance[phase] = r
self._geometric_mean_radius[phase] = gmr
self._wire_positions[phase] = (x, y)
self._phases = sorted(list(conductors.keys()))

@property
def resistance(self):
return self._resistance

@property
def geometric_mean_radius(self):
return self._geometric_mean_radius

@property
def wire_positions(self):
return self._wire_positions

@property
def phases(self):
return self._phases
53 changes: 31 additions & 22 deletions tests/test_carsons.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@
perform_kron_reduction,
)

# `carsons` implements the model entirely in SI metric units, however this
# conversion allows us to enter in impedance as ohm-per-mile in the test
# harness, which means we can lift matrices directly out of the ieee test
# network.
OHM_PER_MILE_TO_OHM_PER_METER = 1 / 1609.344


class ABCN_geometry_line():

""" IEEE 13 Configuration 601 Line Geometry """
@property
def resistance(self):
return {
Expand Down Expand Up @@ -41,15 +45,16 @@ def wire_positions(self):

@property
def phases(self):
return {
'A': 'A',
'B': 'B',
'C': 'C',
'N': 'N',
}
return [
'A',
'B',
'C',
'N',
]


class CBN_geometry_line():
""" IEEE 13 Configuration 603 Line Geometry """

@property
def resistance(self):
Expand Down Expand Up @@ -77,14 +82,15 @@ def wire_positions(self):

@property
def phases(self):
return {
'B': 'B',
'C': 'C',
'N': 'N',
}
return [
'B',
'C',
'N',
]


class CN_geometry_line():
""" IEEE 13 Configuration 605 Line Geometry"""

@property
def resistance(self):
Expand All @@ -109,10 +115,10 @@ def wire_positions(self):

@property
def phases(self):
return {
'C': 'C',
'N': 'N',
}
return [
'C',
'N',
]


class ABCN_balanced_line():
Expand Down Expand Up @@ -146,15 +152,16 @@ def wire_positions(self):

@property
def phases(self):
return {
'A': 'A',
'B': 'B',
'C': 'C',
'N': 'N',
}
return [
'A',
'B',
'C',
'N',
]


def ABCN_line_geometry_phase_impedance():
""" IEEE 13 Configuration 601 Impedance Solution """
return OHM_PER_MILE_TO_OHM_PER_METER * array([
[0.3465 + 1.0179j, 0.1560 + 0.5017j, 0.1580 + 0.4236j],
[0.1560 + 0.5017j, 0.3375 + 1.0478j, 0.1535 + 0.3849j],
Expand Down Expand Up @@ -203,13 +210,15 @@ def ABCN_balanced_z_primitive():


def CBN_line_geometry_phase_impedance():
""" IEEE 13 Configuration 603 Impedance Solution """
return OHM_PER_MILE_TO_OHM_PER_METER * array([
[0.0000 + 0.0000j, 0.0000 + 0.0000j, 0.0000 + 0.0000j],
[0.0000 + 0.0000j, 1.3294 + 1.3471j, 0.2066 + 0.4591j],
[0.0000 + 0.0000j, 0.2066 + 0.4591j, 1.3238 + 1.3569j]])


def CN_line_geometry_phase_impedance():
""" IEEE 13 Configuration 605 Impedance Solution """
return OHM_PER_MILE_TO_OHM_PER_METER * array([
[0.0000 + 0.0000j, 0.0000 + 0.0000j, 0.0000 + 0.0000j],
[0.0000 + 0.0000j, 0.0000 + 0.0000j, 0.0000 + 0.0000j],
Expand Down
46 changes: 46 additions & 0 deletions tests/test_dict_compatibility.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from numpy.testing import assert_array_almost_equal

from .test_carsons import ABCN_line_z_primitive
from carsons.carsons import CarsonsEquations


def test_compatibility_with_dict_of_phases():
class BackwardsCompatibleModel():
def __init__(self):
self.resistance = {
"A": 0.000115575,
"B": 0.000115575,
"C": 0.000115575,
"N": 0.000367852,
}

self.geometric_mean_radius = {
"A": 0.00947938,
"B": 0.00947938,
"C": 0.00947938,
"N": 0.00248107,
}

self.wire_positions = {
"A": (0.762, 8.5344),
"B": (2.1336, 8.5344),
"C": (0, 8.5344),
"N": (1.2192, 7.3152),
}
self.phases = {
"A": "A",
"B": "B",
"C": "C",
"N": "N",
}
# we are compatible models that provide 'phases'
# as a dictionary

model = BackwardsCompatibleModel()

z_primative = CarsonsEquations(model).build_z_primitive()
assert_array_almost_equal(
z_primative,
ABCN_line_z_primitive(),
decimal=4
)
54 changes: 54 additions & 0 deletions tests/test_multiple_neutrals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import numpy
from numpy.testing import assert_array_almost_equal

from carsons.carsons import CarsonsEquations
from tests.helpers import LineModel
from tests.test_carsons import ABCN_line_z_primitive


def test_dual_neutral_model():

model = CarsonsEquations(LineModel({
# resistance gmr (x, y)
# ==========================================
"A": (0.000115575, 0.00947938, (0.762, 8.5344)),
"B": (0.000115575, 0.00947938, (2.1336, 8.5344)),
"N1": (0.000115575, 0.00947938, (0.0, 8.5344)),
"N2": (0.000367852, 0.00248107, (0.0, 7.3152)),
}))
z_primitive = model.build_z_primitive()

# dimensions should include A, B, C and as many neutrals as are described
assert z_primitive.shape == (5, 5)

# because there's no C conductor in the model, expect a row/column of zeros
assert_array_almost_equal(z_primitive[2, 0:], [0+0j]*5)
assert_array_almost_equal(z_primitive[0:, 2], [0+0j]*5)

# if we delete the C row/column, we should get a z_primitive that looks
# like Configuration 601, since the geometry of A/B/C/N is mapped to
# A/B/N1/N2
z_equivalent = z_primitive.copy()
z_equivalent = numpy.delete(z_equivalent, 2, 0)
z_equivalent = numpy.delete(z_equivalent, 2, 1)
z_expected = ABCN_line_z_primitive()
assert_array_almost_equal(z_equivalent, z_expected, decimal=4)


def test_malformed_neutrals_are_ignored():
LINE_WITH_BAD_NEUTRAL_LABEL = LineModel({
# resistance gmr (x, y)
# ==========================================
"A": (0.000115575, 0.00947938, (0.762, 8.5344)),
"B": (0.000115575, 0.00947938, (2.1336, 8.5344)),
"C": (0.000115575, 0.00947938, (0.0, 8.5344)),
"N1": (0.000367852, 0.00248107, (0.0, 7.3152)),
"pN2": (0.000367852, 0.00248107, (1.2192, 7.3152)),
})
model = CarsonsEquations(LINE_WITH_BAD_NEUTRAL_LABEL)
z_primitive = model.build_z_primitive()

assert z_primitive.shape == (4, 4)

z_expected = ABCN_line_z_primitive()
assert_array_almost_equal(z_primitive, z_expected, decimal=4)

0 comments on commit 6919cd5

Please sign in to comment.