public IEnumerable <IdentifiedObject> Transform(CimContext context, IEnumerable <IdentifiedObject> input) { HashSet <PhysicalNetworkModel.IdentifiedObject> dropList = new HashSet <IdentifiedObject>(); List <PhysicalNetworkModel.IdentifiedObject> addList = new List <IdentifiedObject>(); foreach (var inputCimObject in input) { // Find connectivity nodes outside substations if (inputCimObject is ConnectivityNode && !dropList.Contains(inputCimObject) && !inputCimObject.IsInsideSubstation(context)) { ConnectivityNode cn = inputCimObject as ConnectivityNode; // Handle that acls cn relationship might have changed var cnNeighborsx = cn.GetNeighborConductingEquipments(context); // If two acls and we are above low voltage, merge them if (cnNeighborsx.Count(o => o.BaseVoltage > 5000) > 0) { // acls <-> acls if (cnNeighborsx.Count(o => o is ACLineSegmentExt) == 2) { var acls = cnNeighborsx.Where(o => o is ACLineSegmentExt).ToList(); var acls1 = acls[0] as ACLineSegment; var acls2 = acls[1] as ACLineSegment; // NEVER MERGE bool theSame = false; // Compate bch if (acls1.bch != null && acls2.bch != null && !CompareAclsValue(acls1.length.Value, acls1.bch.Value, acls2.length.Value, acls2.bch.Value)) { theSame = false; } // Compate b0ch if (acls1.b0ch != null && acls2.b0ch != null && !CompareAclsValue(acls1.length.Value, acls1.b0ch.Value, acls2.length.Value, acls2.b0ch.Value)) { theSame = false; } // Compare gch if (acls1.gch != null && acls2.gch != null && !CompareAclsValue(acls1.length.Value, acls1.gch.Value, acls2.length.Value, acls2.gch.Value)) { theSame = false; } // Compare g0ch if (acls1.g0ch != null && acls2.g0ch != null && !CompareAclsValue(acls1.length.Value, acls1.g0ch.Value, acls2.length.Value, acls2.g0ch.Value)) { theSame = false; } // Compare r if (acls1.r != null && acls2.r != null && !CompareAclsValue(acls1.length.Value, acls1.r.Value, acls2.length.Value, acls2.r.Value)) { theSame = false; } // Compare r0 if (acls1.r0 != null && acls2.r0 != null && !CompareAclsValue(acls1.length.Value, acls1.r0.Value, acls2.length.Value, acls2.r0.Value)) { theSame = false; } // Compare x if (acls1.x != null && acls2.x != null && !CompareAclsValue(acls1.length.Value, acls1.x.Value, acls2.length.Value, acls2.x.Value)) { theSame = false; } // Compare x0 if (acls1.x0 != null && acls2.x0 != null && !CompareAclsValue(acls1.length.Value, acls1.x0.Value, acls2.length.Value, acls2.x0.Value)) { theSame = false; } // If the cables have the same eletrical charastica, merge them if (theSame) { // ACLS 1 will survive, ACLS 2 and the CN will die dropList.Add(cn); dropList.Add(acls2); // drop acls 2 terminals foreach (var tc in context.GetConnections(acls2)) { dropList.Add(tc.Terminal); } var loc1 = context.GetObject <LocationExt>(acls1.Location.@ref); var loc2 = context.GetObject <LocationExt>(acls2.Location.@ref); LineMerger lm = new LineMerger(); // Convert to NTS geometries lm.Add(GetGeometry(loc1)); lm.Add(GetGeometry(loc2)); // Merge the two line strings var mergedLineList = lm.GetMergedLineStrings(); if (mergedLineList.Count != 1) { throw new Exception("Cannot merge ACLS: " + acls1.mRID + " and " + acls2.mRID); } // Overwrite loc 1 coordinated with merged strings loc1.coordinates = GetPoints((ILineString)mergedLineList[0]).ToArray(); // Sum length acls1.length.Value += acls2.length.Value; // Sum bch if (acls1.bch != null && acls2.bch != null) { acls1.bch.Value += acls2.bch.Value; } // Sum b0ch if (acls1.b0ch != null && acls2.b0ch != null) { acls1.b0ch.Value += acls2.b0ch.Value; } // Sum gch if (acls1.gch != null && acls2.gch != null) { acls1.gch.Value += acls2.gch.Value; } // Sum g0ch if (acls1.g0ch != null && acls2.g0ch != null) { acls1.g0ch.Value += acls2.g0ch.Value; } // Sum r if (acls1.r != null && acls2.r != null) { acls1.r.Value += acls2.r.Value; } // Sum r0 if (acls1.r0 != null && acls2.r0 != null) { acls1.r0.Value += acls2.r0.Value; } // Sum x if (acls1.x != null && acls2.x != null) { acls1.x.Value += acls2.x.Value; } // Sum x0 if (acls1.x0 != null && acls2.x0 != null) { acls1.x0.Value += acls2.x0.Value; } // Find cn in the other end of ACLS 2 var acls2otherEndCn = context.GetConnections(acls2).Find(o => o.ConnectivityNode != cn); // Get terminal of ACLS 1 that point to ACLS 2 var acls1Terminal = acls1.GetTerminal(acls2, true, context); // Disconnect ACLS 2 terminals var acls2connections = context.GetConnections(acls2); List <Terminal> terminalsToDisconnect = new List <Terminal>(); foreach (var acls2con in acls2connections) { terminalsToDisconnect.Add(acls2con.Terminal); } foreach (var t2d in terminalsToDisconnect) { context.DisconnectTerminalFromConnectitityNode(t2d); } // Change terminal of ACLS 1 to point to ACLS 2 other end CN context.ConnectTerminalToAnotherConnectitityNode(acls1Terminal, acls2otherEndCn.ConnectivityNode); } else { // Cable are not the same, we need to add a susbstation to act as a junction // Create muffe station var st = new PhysicalNetworkModel.Substation(); st.mRID = Guid.NewGuid().ToString(); st.name = "Junction"; st.PSRType = "Junction"; addList.Add(st); // Create voltage level var vl = new PhysicalNetworkModel.VoltageLevel(); vl.mRID = Guid.NewGuid().ToString(); vl.BaseVoltage = acls1.BaseVoltage; vl.name = "VL"; vl.EquipmentContainer1 = new VoltageLevelEquipmentContainer() { @ref = st.mRID }; addList.Add(vl); // Relate cn to voltage level if (_mappingContext.ConnectivityNodeToVoltageLevel.ContainsKey(cn)) { _mappingContext.ConnectivityNodeToVoltageLevel.Remove(cn); } _mappingContext.ConnectivityNodeToVoltageLevel.Add(cn, vl); } } // <> 2 kabler else { // Create muffe station var st = new PhysicalNetworkModel.Substation(); st.mRID = Guid.NewGuid().ToString(); st.name = "MUFFE"; st.PSRType = "Junction"; addList.Add(st); // Create voltage level var vl = new PhysicalNetworkModel.VoltageLevel(); vl.mRID = Guid.NewGuid().ToString(); vl.BaseVoltage = cnNeighborsx[0].BaseVoltage; vl.name = "VL"; vl.EquipmentContainer1 = new VoltageLevelEquipmentContainer() { @ref = st.mRID }; addList.Add(vl); // Relate cn to voltage level if (_mappingContext.ConnectivityNodeToVoltageLevel.ContainsKey(cn)) { _mappingContext.ConnectivityNodeToVoltageLevel.Remove(cn); } _mappingContext.ConnectivityNodeToVoltageLevel.Add(cn, vl); } } } } // return objects, except the one dropped foreach (var inputObj in input) { if (!dropList.Contains(inputObj)) { yield return(inputObj); } } // yield added objects, foreach (var inputObj in addList) { yield return(inputObj); } }