private OutageTopologyElement GetSwitch(long gid) { OutageTopologyElement element; if (outageTopologyModel.GetElementByGid(gid, out element)) { while (!IsSwitch(element.DmsType)) { if (!outageTopologyModel.GetElementByGid(element.FirstEnd, out element)) { break; } } } return(element); }
public IOutageTopologyModel ConvertTopologyToOMSModel(ITopology topology) { logger.LogDebug("Topology to OMS model convert started."); IOutageTopologyModel outageTopologyModel = new OutageTopologyModel(); Stack <long> stack = new Stack <long>(); var reclosers = Provider.Instance.ModelProvider.GetReclosers(); outageTopologyModel.FirstNode = topology.FirstNode; stack.Push(topology.FirstNode); List <long> secondEnd = new List <long>(); long nextElement = 0; long nextElementGid = 0; ITopologyElement element; bool isOpen; while (stack.Count > 0) { nextElementGid = stack.Pop(); if (topology.GetElementByGid(nextElementGid, out element)) { secondEnd.Clear(); if (!reclosers.Contains(nextElementGid)) { foreach (var child in element.SecondEnd) { nextElement = child.Id; if (ModelCodeHelper.ExtractTypeFromGlobalId(nextElement) == 0) { try { Field field = child as Field; nextElement = field.Members.First().Id; } catch (Exception) { logger.LogError($"[TopologyConverter] Error while getting field in Topology to OMSModel convert. Element is not field or field is empty."); } } secondEnd.Add(nextElement); stack.Push(nextElement); } } isOpen = false; foreach (var meausrementGid in element.Measurements.Keys) { if (Provider.Instance.MeasurementProvider.TryGetDiscreteMeasurement(meausrementGid, out DiscreteMeasurement discreteMeasurement)) { isOpen = discreteMeasurement.CurrentOpen; } } if (!outageTopologyModel.GetElementByGid(element.Id, out var _)) { outageTopologyModel.AddElement( new OutageTopologyElement(element.Id) { FirstEnd = (element.FirstEnd != null) ? element.FirstEnd.Id : 0, DmsType = element.DmsType, IsRemote = element.IsRemote, IsActive = element.IsActive, SecondEnd = new List <long>(secondEnd), NoReclosing = element.NoReclosing, IsOpen = isOpen }); } } else { logger.LogWarn($"[TopologyConverter] Error while getting topology element from topology. It does not exist in topology."); } } logger.LogDebug("Topology to OMSModel convert finished successfully."); return(outageTopologyModel); }
/// <summary> /// /// </summary> /// <param name="algorithm"></param> /// <param name="topology"></param> /// <returns>ConditionalValue with HeadElementGid as value - HasValue: false indicates that task ended unsuccessfully, value will never be null and will represent the id of the task -> HeadElementGid</returns> private async Task <ConditionalValue <long> > StartIndividualAlgorithmCycle(IsolationAlgorithm algorithm, OutageTopologyModel topology) { var algorithmBaseLogString = $"{baseLogString} [HeadBreakerGid: 0x{algorithm.HeadBreakerGid:X16}]"; //END CONDITION - poslednji otvoren brejker se nije otvorio vise od 'cycleUpperLimit' milisekundi => on predstavlja prvu optimalnu izolacionu tacku if (algorithm.CycleCounter * CycleInterval >= CycleUpperLimit) { Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => END CONDITION: {algorithm.CycleCounter} ms * {CycleInterval} ms > {CycleUpperLimit} ms."); var success = await FinishIndividualAlgorithmCycle(algorithm, topology); return(new ConditionalValue <long>(success, algorithm.HeadBreakerGid)); } else { Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => END CONDITION NOT MET: {algorithm.CycleCounter} ms * {CycleInterval} ms <= {CycleUpperLimit} ms."); } #region Check if HeadBreaker has OPENED after the last cycle var result = await MonitoredHeadBreakerMeasurements.TryGetValueAsync(algorithm.HeadBreakerMeasurementGid); if (!result.HasValue) { Logger.LogError($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => HeadBreakerMeasurement with gid: 0x{algorithm.HeadBreakerMeasurementGid:X16} not found in {ReliableDictionaryNames.MonitoredHeadBreakerMeasurements}."); return(new ConditionalValue <long>(false, algorithm.HeadBreakerGid)); } var headMeasurementData = result.Value; if (headMeasurementData.Value == (ushort)DiscreteCommandingType.CLOSE) { Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => HeadBreaker is CLOSED."); //by exiting now we apply the logical WAITING (cycle mechanism in RunAsync): //1) For HeadBreaker to open => moving to next breaker //2) For "time" to run up => FinishIndividualAlgorithmCycle //counting cycles from after the command was successfully executed var commandsCount = await CommandedElements.GetCountAsync(); if (commandsCount == 0) { algorithm.CycleCounter++; await StartedIsolationAlgorithms.SetAsync(algorithm.HeadBreakerGid, algorithm); Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => AlgorithCycleCounter set to {algorithm.CycleCounter}."); } else { Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Skipping the cycle and waiting for {commandsCount} commands to be executed. HEAD is CLOSED. AlgorithCycleCounter remains set on {algorithm.CycleCounter}."); } return(new ConditionalValue <long>(true, algorithm.HeadBreakerGid)); } else if (headMeasurementData.Value == (ushort)DiscreteCommandingType.OPEN) { //skipping untill all commands were successfully executed var commandsCount = await CommandedElements.GetCountAsync(); if (commandsCount > 0) { Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Skipping the cycle and waiting for {commandsCount} commands to be executed. HEAD is OPENED. AlgorithCycleCounter remains set on {algorithm.CycleCounter}."); return(new ConditionalValue <long>(true, algorithm.HeadBreakerGid)); } } else { Logger.LogError($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => headMeasurementData.Value is {headMeasurementData.Value} and cannot be casted to {typeof(DiscreteCommandingType)}."); return(new ConditionalValue <long>(false, algorithm.HeadBreakerGid)); } #endregion Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => HeadBreaker is OPENED."); //Closing current breaker, before moving to the next breaker var commands = new Dictionary <long, DiscreteCommandingType>(); if (algorithm.CurrentBreakerGid != algorithm.HeadBreakerGid) { Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Preaparing command to CLOSE the current breaker 0x{algorithm.CurrentBreakerGid:X16}"); commands.Add(algorithm.CurrentBreakerGid, DiscreteCommandingType.CLOSE); } algorithm.CycleCounter = 0; //moving to the next breaker algorithm.CurrentBreakerGid = lifecycleHelper.GetNextBreaker(algorithm.CurrentBreakerGid, topology); Logger.LogDebug($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Next breaker gid is 0x{algorithm.CurrentBreakerGid:X16}."); if (algorithm.CurrentBreakerGid <= 0 || !topology.GetElementByGid(algorithm.CurrentBreakerGid, out _)) { Logger.LogError($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => HeadBreakerMeasurement with gid: 0x{algorithm.HeadBreakerMeasurementGid:X16} not found in {ReliableDictionaryNames.MonitoredHeadBreakerMeasurements}."); return(new ConditionalValue <long>(false, algorithm.HeadBreakerGid)); } var enumerableCommandedElements = await CommandedElements.GetEnumerableDictionaryAsync(); //reaching the END of the FEEDER - ending the algorithm if (algorithm.CurrentBreakerGid == algorithm.RecloserGid) { string message = $"{algorithmBaseLogString} StartIndividualAlgorithmCycle => End of the feeder, no outage detected."; Logger.LogWarning(message); //TODO: HOW TO HANDEL - archived, deleted.... await SendCommands(algorithm, commands, enumerableCommandedElements); return(new ConditionalValue <long>(false, algorithm.HeadBreakerGid)); } if (!commands.ContainsKey(algorithm.CurrentBreakerGid) && !commands.ContainsKey(algorithm.HeadBreakerGid)) { commands.Add(algorithm.CurrentBreakerGid, DiscreteCommandingType.OPEN); Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Preaparing command to OPEN the current breaker 0x{algorithm.CurrentBreakerGid:X16}"); commands.Add(algorithm.HeadBreakerGid, DiscreteCommandingType.CLOSE); Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Preaparing command to CLOSE the head breaker 0x{algorithm.HeadBreakerGid:X16}"); } if (await SendCommands(algorithm, commands, enumerableCommandedElements)) { Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Commands sent with success."); return(new ConditionalValue <long>(true, algorithm.HeadBreakerGid)); } else { Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Send commands failed."); return(new ConditionalValue <long>(false, algorithm.HeadBreakerGid)); } }
private async Task <bool> StartLocationAndIsolationAlgorithm(OutageEntity outageEntity, OutageTopologyModel topology) { long reportedGid = outageEntity.DefaultIsolationPoints.First().EquipmentId; if (!topology.GetElementByGid(reportedGid, out OutageTopologyElement topologyElement)) { Logger.LogError($"{baseLogString} StartLocationAndIsolationAlgorithm => element with gid 0x{reportedGid:X16} not found in outage topology model."); return(false); } long upBreaker; long outageElementGid = -1; Logger.LogInformation($"{baseLogString} StartLocationAndIsolationAlgorithm => Entering 10 sec delay."); await Task.Delay(10_000); Logger.LogInformation($"{baseLogString} StartLocationAndIsolationAlgorithm => 10 sec delay ended."); var outageSimulatorClient = OutageSimulatorClient.CreateClient(); var outageModelAccessClient = OutageModelAccessClient.CreateClient(); //Da li je prijaveljen element OutageElement if (await outageSimulatorClient.IsOutageElement(reportedGid)) { outageElementGid = reportedGid; } //Da li je mozda na ACL-novima ispod prijavljenog elementa else { for (int i = 0; i < topologyElement.SecondEnd.Count; i++) { var potentialOutageElementGid = topologyElement.SecondEnd[i]; if (!(await outageSimulatorClient.IsOutageElement(potentialOutageElementGid))) { continue; } if (outageElementGid == -1) { outageElementGid = potentialOutageElementGid; outageEntity.OutageElementGid = outageElementGid; //outageEntity.AffectedConsumers = await lifecycleHelper.GetAffectedConsumersFromDatabase(lifecycleHelper.GetAffectedConsumers(outageElementGid, topology, NetworkType.NON_SCADA_NETWORK)); } else { //KAKO SE ULAZI U OVAJ ELSE? => u else se ulazi tako sto se ide kroz for i prvi element se oznaci kao outage element, zatim se pronaje jos neki... znaci ovo je nacin da se kreira drugi, treci outage, na racvanju ispod elementa, po for-u.... var entity = new OutageEntity() { OutageElementGid = potentialOutageElementGid, ReportTime = DateTime.UtcNow }; await outageModelAccessClient.AddOutage(entity); } } } //Tragamo za ACL-om gore ka source-u while (outageElementGid == -1 && !topologyElement.IsRemote && topologyElement.DmsType != "ENERGYSOURCE") { if (await outageSimulatorClient.IsOutageElement(topologyElement.Id)) { outageElementGid = topologyElement.Id; outageEntity.OutageElementGid = outageElementGid; } topology.GetElementByGid(topologyElement.FirstEnd, out topologyElement); } if (outageElementGid == -1) { outageEntity.OutageState = OutageState.REMOVED; await outageModelAccessClient.RemoveOutage(outageEntity); Logger.LogError($"{baseLogString} StartLocationAndIsolationAlgorithm => End of feeder no outage detected."); return(false); } topology.GetElementByGidFirstEnd(outageEntity.OutageElementGid, out topologyElement); while (topologyElement.DmsType != "BREAKER") { topology.GetElementByGidFirstEnd(topologyElement.Id, out topologyElement); } upBreaker = topologyElement.Id; long nextBreaker = lifecycleHelper.GetNextBreaker(outageEntity.OutageElementGid, topology); if (!topology.OutageTopology.ContainsKey(nextBreaker)) { string message = $"{baseLogString} StartLocationAndIsolationAlgorithm => Breaker (next breaker) with id: 0x{nextBreaker:X16} is not in topology"; Logger.LogError(message); throw new Exception(message); } long outageElement = topology.OutageTopology[nextBreaker].FirstEnd; if (!topology.OutageTopology[upBreaker].SecondEnd.Contains(outageElement)) { string message = $"{baseLogString} StartLocationAndIsolationAlgorithm => Outage element with gid: 0x{outageElement:X16} is not on a second end of current breaker id"; Logger.LogError(message); throw new Exception(message); } outageEntity.OptimumIsolationPoints = await lifecycleHelper.GetEquipmentEntityAsync(new List <long>() { upBreaker, nextBreaker }); outageEntity.IsolatedTime = DateTime.UtcNow; outageEntity.OutageState = OutageState.ISOLATED; await outageModelAccessClient.UpdateOutage(outageEntity); var commands = new Dictionary <long, DiscreteCommandingType> { { upBreaker, DiscreteCommandingType.OPEN }, { nextBreaker, DiscreteCommandingType.OPEN }, }; var enumerableCommandedElements = await CommandedElements.GetEnumerableDictionaryAsync(); if (!await lifecycleHelper.SendMultipleScadaCommandAsync(commands, enumerableCommandedElements, CommandOriginType.LOCATION_AND_ISOLATING_ALGORITHM_COMMAND)) { string message = $"{baseLogString} StartLocationAndIsolationAlgorithm => Sending multiple command failed."; Logger.LogError(message); return(false); } commands.Keys.ToList().ForEach(async commandedElementGid => { await ElementsToBeIgnoredInReportPotentialOutage.SetAsync(commandedElementGid, DateTime.UtcNow); Logger.LogDebug($"{baseLogString} SendCommands => Element 0x{commandedElementGid:X16} set to collection '{ReliableDictionaryNames.ElementsToBeIgnoredInReportPotentialOutage}' at {DateTime.UtcNow}."); }); return(true); }
public async Task Start(List <long> calls) { Logger.LogDebug("Starting tracking algorithm."); //on every start tracking algorithm get up to date outage topology model var topologyProviderClient = TopologyProviderClient.CreateClient(); outageTopologyModel = await topologyProviderClient.GetOMSModel(); this.potentialOutages = LocateSwitchesUsingCalls(calls); this.outages = new List <long>(); HashSet <long> visited = new HashSet <long>(); bool foundOutage = false; long currentGid, previousGid; currentGid = this.potentialOutages[0]; try { while (this.potentialOutages.Count > 0) { currentGid = this.potentialOutages[0]; previousGid = currentGid; this.outages.Add(currentGid); outageTopologyModel.GetElementByGid(currentGid, out OutageTopologyElement topologyElement); this.potentialOutages.Remove(currentGid); while (topologyElement.DmsType != "ENERGYSOURCE" && !topologyElement.IsRemote && this.potentialOutages.Count > 0) { foundOutage = false; if (TraceDFS(visited, topologyElement, foundOutage)) { this.outages.Remove(previousGid); this.outages.Add(currentGid); previousGid = currentGid; } topologyElement = GetSwitch(topologyElement.FirstEnd); if (topologyElement == null) { break; } currentGid = topologyElement.Id; } } } catch (Exception ex) { string message = $"Tracing algorithm failed with error: {ex.Message}"; Logger.LogError(message); Console.WriteLine(message); } var reportOutageClient = PotentialOutageReportingClient.CreateClient(); foreach (var potentialOutageElementGid in this.outages) { var ceModelProviderClient = CeModelProviderClient.CreateClient(); if (!await ceModelProviderClient.IsRecloser(potentialOutageElementGid)) { //TODO: razdvojiti metode scada, noScada await reportOutageClient.ReportPotentialOutage(potentialOutageElementGid, CommandOriginType.NON_SCADA_OUTAGE, NetworkType.NON_SCADA_NETWORK); } else { Logger.LogDebug($"{baseLogString} Start => Element with gid 0x{potentialOutageElementGid:X16} is a Recloser. ReportPotentialOutage call is not required."); } } }