Commits

Stefan Scherfke committed c9153c0

Can now parse locations and position points.

Comments (0)

Files changed (4)

cim2busbranch/cim2bb.py

         *tnodes* and handels all connected primary equipment to parameterize
         the bus and/or creat :class:`topology.Generator` instances.
 
-        Transformer windings are ignored and handled by
+        Power transformers are ignored and handled by
         :meth:`_create_branches`.
 
         """
         buses = {}
         generators = {}
-        twindings = []
+        power_transformers = set()
         swingbus = None
 
         for tnode, prim_equip in tnodes.items():
             btype = topology.bus_type.PQ
             names = []
             cim_classes = []
+            position_points = set()
 
             for equip in prim_equip:
+                equip_cls = equip.__class__.__name__
+
                 names.append(equip.name or equip.mRID)
-                equip_cls = equip.__class__.__name__
                 cim_classes.append(equip_cls)
+                position_points |= self._get_position_points(equip)
 
                 if (equip_cls == 'BusbarSection' and
                         equip.aliasName == 'SwingBus'):
                     swingbus = equip
                     btype = topology.bus_type.REF
 
+                elif equip_cls == 'TransformerWinding':
+                    power_transformers.add(equip.PowerTransformer)
+
                 # Todo: Check other equipment classes
             base_voltage = self._get_base_voltage(tnode)
 
                     vm=1.0,
                     va=0.0,
                     cim_classes=sorted(cim_classes),
-                    pos=None,
+                    pos=position_points,
                 )
 
         assert swingbus, 'No swing bus found.'
 
-        return buses, generators, twindings
+        return buses, generators, power_transformers
+
+    def _get_position_points(self, equipment):
+        """
+        Returns the set of position points (:class:`topology.Point`) for
+        *equipment*.
+
+        """
+        loc = equipment.Location
+        if not loc:
+            return set()
+
+        pos = set([topology.Point(float(p.xPosition), float(p.yPosition))
+                for p in loc.PositionPoints])
+
+        return pos
 
     def _get_base_voltage(self, tnode):
         """

cim2busbranch/test/data/TestCaseB.xml

         <cim:BaseVoltage.nominalVoltage>20</cim:BaseVoltage.nominalVoltage>
     </cim:BaseVoltage>
 
+    <cim:PositionPoint rdf:ID="Transformer20kV_P">
+        <cim:PositionPoint.xPosition>0</cim:PositionPoint.xPosition>
+        <cim:PositionPoint.yPosition>2</cim:PositionPoint.yPosition>
+    </cim:PositionPoint>
+    <cim:Location rdf:ID="Transformer20kV_L">
+        <cim:Location.PositionPoints rdf:resource="#Transformer20kV_P"/>
+    </cim:Location>
+    <cim:PositionPoint rdf:ID="Bus1_P">
+        <cim:PositionPoint.xPosition>5</cim:PositionPoint.xPosition>
+        <cim:PositionPoint.yPosition>2</cim:PositionPoint.yPosition>
+    </cim:PositionPoint>
+    <cim:Location rdf:ID="Bus1_L">
+        <cim:Location.PositionPoints rdf:resource="#Bus1_P"/>
+    </cim:Location>
+    <cim:PositionPoint rdf:ID="Bus2_P">
+        <cim:PositionPoint.xPosition>1</cim:PositionPoint.xPosition>
+        <cim:PositionPoint.yPosition>0</cim:PositionPoint.yPosition>
+    </cim:PositionPoint>
+    <cim:Location rdf:ID="Bus2_L">
+        <cim:Location.PositionPoints rdf:resource="#Bus2_P"/>
+    </cim:Location>
+    <cim:PositionPoint rdf:ID="Bus3_P">
+        <cim:PositionPoint.xPosition>4</cim:PositionPoint.xPosition>
+        <cim:PositionPoint.yPosition>0</cim:PositionPoint.yPosition>
+    </cim:PositionPoint>
+    <cim:Location rdf:ID="Bus3_L">
+        <cim:Location.PositionPoints rdf:resource="#Bus3_P"/>
+    </cim:Location>
+
     <cim:ConnectivityNode rdf:ID="Transformer20kV_C">
         <cim:IdentifiedObject.mRID>Transformer20kV_C</cim:IdentifiedObject.mRID>
         <cim:ConnectivityNode.ConnectivityNodeContainer rdf:resource="#VoltageLevel20kV"/>
     <cim:BusbarSection rdf:ID="Transformer20kV">
         <cim:IdentifiedObject.mRID>Transformer20kV</cim:IdentifiedObject.mRID>
         <cim:IdentifiedObject.aliasName>SwingBus</cim:IdentifiedObject.aliasName>
+        <cim:PowerSystemResource.Location rdf:resource="#Transformer20kV_L"/>
         <cim:ConductingEquipment.Terminals rdf:resource="#Transformer20kV_T"/>
     </cim:BusbarSection>
     <cim:Terminal rdf:ID="Transformer20kV_T">
     <cim:EnergyConsumer rdf:ID="Residential">
         <cim:IdentifiedObject.mRID>Residential</cim:IdentifiedObject.mRID>
         <cim:IdentifiedObject.name>Residential</cim:IdentifiedObject.name>
+        <cim:PowerSystemResource.Location rdf:resource="#Bus1_L"/>
         <cim:ConductingEquipment.Terminals rdf:resource="#Residential_T"/>
         <cim:EnergyConsumer.pfixed.value>800</cim:EnergyConsumer.pfixed.value>
         <!-- <cim:EnergyConsumer.pfixed.multiplier>k</cim:EnergyConsumer.pfixed.multiplier> -->
     <cim:SynchronousMachine rdf:ID="WEC">
         <cim:IdentifiedObject.mRID>WEC</cim:IdentifiedObject.mRID>
         <cim:IdentifiedObject.name>WEC</cim:IdentifiedObject.name>
+        <cim:PowerSystemResource.Location rdf:resource="#Bus2_L"/>
         <cim:ConductingEquipment.Terminals rdf:resource="#WEC_T"/>
         <cim:SynchronousMachine.baseQ.value>280</cim:SynchronousMachine.baseQ.value>
         <!-- <cim:SynchronousMachine.baseQ.multiplier>k</cim:SynchronousMachine.baseQ.multiplier> -->
     <cim:EnergyConsumer rdf:ID="Industry">
         <cim:IdentifiedObject.mRID>Industry</cim:IdentifiedObject.mRID>
         <cim:IdentifiedObject.name>Industry</cim:IdentifiedObject.name>
+        <cim:PowerSystemResource.Location rdf:resource="#Bus3_L"/>
         <cim:ConductingEquipment.Terminals rdf:resource="#Industry_T"/>
         <cim:EnergyConsumer.pfixed.value>850</cim:EnergyConsumer.pfixed.value>
         <!-- <cim:EnergyConsumer.pfixed.multiplier>k</cim:EnergyConsumer.pfixed.multiplier> -->

cim2busbranch/test/test_cim2bb.py

     'TestCaseB.xml': {
         'base_power': 10,
         'num_tnodes': 4,
-        'num_branches': 4,
+        'num_lines': 4,
         'bus_attr': sorted([
             ('Industry 2, Transformer20kV', 3, 0, 0, 1, 0,
-                ['BusbarSection', 'EnergyConsumer'], None),
+                ['BusbarSection', 'EnergyConsumer'], set([(0, 2)])),
             ('PV, Residential', 1, 0, 0, 1, 0,
-                ['EnergyConsumer', 'EnergySource'], None),
+                ['EnergyConsumer', 'EnergySource'], set([(5, 2)])),
             ('WEC', 1, 0, 0, 1, 0,
-                ['SynchronousMachine'], None),
+                ['SynchronousMachine'], set([(1, 0)])),
             ('Industry', 1, 0, 0, 1, 0,
-                ['EnergyConsumer'], None),
+                ['EnergyConsumer'], set([(4, 0)])),
         ]),
+        'num_transformers': 0,
     },
     'TestCaseB_gen.xml': {
         'base_power': 10,
         'num_tnodes': 4,
-        'num_branches': 4,
+        'num_lines': 4,
         'bus_attr': sorted([
-            ('Transformer20kV', 3, 0, 0, 1, 0, ['BusbarSection'], None),
-            ('Bus1', 1, 0, 0, 1, 0, ['BusbarSection'], None),
-            ('Bus2', 1, 0, 0, 1, 0, ['BusbarSection'], None),
-            ('Bus3', 1, 0, 0, 1, 0, ['BusbarSection'], None),
+            ('Transformer20kV', 3, 0, 0, 1, 0, ['BusbarSection'], set()),
+            ('Bus1', 1, 0, 0, 1, 0, ['BusbarSection'], set()),
+            ('Bus2', 1, 0, 0, 1, 0, ['BusbarSection'], set()),
+            ('Bus3', 1, 0, 0, 1, 0, ['BusbarSection'], set()),
         ]),
+        'num_transformers': 0,
     },
     'Transformer.xml': {
         'base_power': 1,
         'num_tnodes': 4,
-        'num_branches': 1,
+        'num_lines': 1,
         'bus_attr': sorted([
             ('Busbar17kV, GenAlpha, PT_17132_W1, PT_1733_W1', 3, 0, 0, 1, 0,
                 ['BusbarSection', 'SynchronousMachine', 'TransformerWinding',
-                'TransformerWinding'], None),
+                'TransformerWinding'], set()),
             ('LoadA, PT_1733_W2', 1, 0, 0, 1, 0, ['EnergyConsumer',
-                'TransformerWinding'], None),
-            ('LoadB', 1, 0, 0, 1, 0, ['EnergyConsumer'], None),
-            ('PT_17132_W2', 1, 0, 0, 1, 0, ['TransformerWinding'], None),
-        ])
+                'TransformerWinding'], set()),
+            ('LoadB', 1, 0, 0, 1, 0, ['EnergyConsumer'], set()),
+            ('PT_17132_W2', 1, 0, 0, 1, 0, ['TransformerWinding'], set()),
+        ]),
+        'num_transformers': 2,
     },
 }
 
     cim_objects = RDFXMLReader.cimread(converter.cim_file)
     base_power, tnodes, lines = converter._iterate_prim_eq(cim_objects)
 
-    buses, gens, tw = converter._create_buses(tnodes)
+    buses, gens, pt = converter._create_buses(tnodes)
     data = sorted([
             (b.name, b.btype, b.pd, b.qd, b.vm, b.va, b.cim_classes, b.pos)
                 for b in buses.values()
     assert data == results['bus_attr']
 
     assert gens == {}
-    assert tw == []
+    assert len(pt) == results['num_transformers']
+
+
+def test_get_position_points(converter, results):
+    get_cls = converter._get_cls
+    BusbarSection = get_cls('BusbarSection')
+    Location = get_cls('Location')
+    PositionPoint = get_cls('PositionPoint')
+
+    bs = BusbarSection()
+    pp = converter._get_position_points(bs)
+    assert pp == set()
+
+    loc = Location()
+    bs.Location = loc
+    pp = converter._get_position_points(bs)
+    assert pp == set()
+
+    loc.addPositionPoints(PositionPoint(xPosition=1, yPosition=2))
+    pp = converter._get_position_points(bs)
+    assert pp == set([(1, 2)])
+
+    loc.addPositionPoints(PositionPoint(xPosition=2, yPosition=2))
+    pp = converter._get_position_points(bs)
+    assert pp == set([(1, 2), (2, 2)])
 
 
 def test_get_base_voltage(converter, results):
         assert tnode.__class__.__name__ == 'TopologicalNode'
         assert len(equip) >= 1
 
-    assert len(branches) == results['num_branches']
+    assert len(branches) == results['num_lines']
     for branch in branches:
         assert branch.__class__.__name__ == 'ACLineSegment'
 

cim2busbranch/topology.py

     ISOLATED=4,
 )
 
+Point = collections.namedtuple('Point', 'x, y')
+
 
 class Bus(object):
     """
         """Classes of CIM components that were connected to this bus."""
 
         self.pos = pos
-        """Position (x, y) of that bus."""
+        """Set of position points (x, y) of that bus."""
 
         self._pd_orig = pd
         self._qd_orig = qd