private DataSeries GetVAllSeries(VICycleDataGroup viCycleDataGroup)
        {
            DataSeries dataSeries = new DataSeries();

            for (int i = 0; i < viCycleDataGroup.VA.RMS.DataPoints.Count; i++)
            {
                dataSeries.DataPoints.Add(m_getVAllPoint(viCycleDataGroup.VA.RMS[i], viCycleDataGroup.VB.RMS[i], viCycleDataGroup.VC.RMS[i]));
            }

            return(dataSeries);
        }
        private void DetectDisturbances(DataGroup dataGroup, VICycleDataGroup viCycleDataGroup)
        {
            List <Range <int> > aPhaseDisturbanceRanges  = DetectDisturbanceRanges(ToPerUnit(viCycleDataGroup.VA?.RMS));
            List <Range <int> > bPhaseDisturbanceRanges  = DetectDisturbanceRanges(ToPerUnit(viCycleDataGroup.VB?.RMS));
            List <Range <int> > cPhaseDisturbanceRanges  = DetectDisturbanceRanges(ToPerUnit(viCycleDataGroup.VC?.RMS));
            List <Range <int> > abPhaseDisturbanceRanges = DetectDisturbanceRanges(ToPerUnit(viCycleDataGroup.VAB?.RMS));
            List <Range <int> > bcPhaseDisturbanceRanges = DetectDisturbanceRanges(ToPerUnit(viCycleDataGroup.VBC?.RMS));
            List <Range <int> > caPhaseDisturbanceRanges = DetectDisturbanceRanges(ToPerUnit(viCycleDataGroup.VCA?.RMS));

            List <Disturbance> disturbanceList = aPhaseDisturbanceRanges.Select(range => ToDisturbance(viCycleDataGroup.VA.RMS, range, Phase.AN))
                                                 .Concat(bPhaseDisturbanceRanges.Select(range => ToDisturbance(viCycleDataGroup.VB.RMS, range, Phase.BN)))
                                                 .Concat(cPhaseDisturbanceRanges.Select(range => ToDisturbance(viCycleDataGroup.VC.RMS, range, Phase.CN)))
                                                 .Concat(abPhaseDisturbanceRanges.Select(range => ToDisturbance(viCycleDataGroup.VAB.RMS, range, Phase.AB)))
                                                 .Concat(bcPhaseDisturbanceRanges.Select(range => ToDisturbance(viCycleDataGroup.VBC.RMS, range, Phase.BC)))
                                                 .Concat(caPhaseDisturbanceRanges.Select(range => ToDisturbance(viCycleDataGroup.VCA.RMS, range, Phase.CA)))
                                                 .ToList();

            IEnumerable <Range <int> > allDisturbanceRanges = aPhaseDisturbanceRanges
                                                              .Concat(bPhaseDisturbanceRanges)
                                                              .Concat(cPhaseDisturbanceRanges)
                                                              .Concat(abPhaseDisturbanceRanges)
                                                              .Concat(bcPhaseDisturbanceRanges)
                                                              .Concat(caPhaseDisturbanceRanges);

            IEnumerable <Disturbance> worstDisturbances = Range <int> .MergeAllOverlapping(allDisturbanceRanges)
                                                          .Select(range =>
            {
                Disturbance worst = null;

                foreach (Disturbance disturbance in disturbanceList.Where(disturbance => ToRange(disturbance).Overlaps(range)))
                {
                    if ((object)worst == null || m_isMoreSevere(disturbance.PerUnitMagnitude, worst.PerUnitMagnitude))
                    {
                        worst = disturbance;
                    }
                }

                worst       = worst.Clone();
                worst.Phase = Phase.Worst;
                return(worst);
            });

            disturbanceList.AddRange(worstDisturbances);

            if (disturbanceList.Any())
            {
                m_disturbances.Add(dataGroup, disturbanceList);
            }
        }
        private void DetectDisturbances(DataGroup dataGroup, VICycleDataGroup viCycleDataGroup)
        {
            double     nominalVoltage           = dataGroup.Line.VoltageKV * 1000.0D / Sqrt3;
            double     nominalVoltageReciprocal = 1.0D / nominalVoltage;
            DataSeries vAll = GetVAllSeries(viCycleDataGroup);

            List <Range <int> > aPhaseDisturbanceRanges = DetectDisturbanceRanges(viCycleDataGroup.VA.RMS.Multiply(nominalVoltageReciprocal));
            List <Range <int> > bPhaseDisturbanceRanges = DetectDisturbanceRanges(viCycleDataGroup.VB.RMS.Multiply(nominalVoltageReciprocal));
            List <Range <int> > cPhaseDisturbanceRanges = DetectDisturbanceRanges(viCycleDataGroup.VC.RMS.Multiply(nominalVoltageReciprocal));
            List <Range <int> > allDisturbanceRanges    = DetectDisturbanceRanges(vAll.Multiply(nominalVoltageReciprocal));

            List <Disturbance> disturbanceList = aPhaseDisturbanceRanges.Select(range => ToDisturbance(viCycleDataGroup.VA.RMS, range, Phase.AN))
                                                 .Concat(bPhaseDisturbanceRanges.Select(range => ToDisturbance(viCycleDataGroup.VB.RMS, range, Phase.BN)))
                                                 .Concat(cPhaseDisturbanceRanges.Select(range => ToDisturbance(viCycleDataGroup.VC.RMS, range, Phase.CN)))
                                                 .Concat(allDisturbanceRanges.Select(range => ToDisturbance(vAll, range, Phase.None)))
                                                 .ToList();

            m_disturbances.Add(dataGroup, disturbanceList);
        }
        public void Initialize(MeterDataSet meterDataSet)
        {
            ConnectionStringParser.ParseConnectionString(meterDataSet.ConnectionString, this);

            m_disturbances = new Dictionary <DataGroup, List <Disturbance> >();

            CycleDataResource cycleDataResource = meterDataSet.GetResource <CycleDataResource>();

            int lineCount = meterDataSet.Meter.MeterLines.Count;

            for (int i = 0; i < cycleDataResource.DataGroups.Count; i++)
            {
                DataGroup        dataGroup        = cycleDataResource.DataGroups[i];
                VICycleDataGroup viCycleDataGroup = cycleDataResource.VICycleDataGroups[i];
                Range <DateTime> eventDateRange   = new Range <DateTime>(dataGroup.StartTime, dataGroup.EndTime);

                if (lineCount == 1 && dataGroup.Disturbances.Count > 0)
                {
                    ProcessReportedDisturbances(meterDataSet.Meter, dataGroup);
                }
                else
                {
                    DetectDisturbances(dataGroup, viCycleDataGroup);
                }
            }

            DataGroupsResource dataGroupsResource = meterDataSet.GetResource <DataGroupsResource>();

            foreach (DataGroup dataGroup in dataGroupsResource.DataGroups)
            {
                if (dataGroup.DataSeries.Count > 0)
                {
                    continue;
                }

                if (lineCount == 1 && dataGroup.Disturbances.Count > 0)
                {
                    ProcessReportedDisturbances(meterDataSet.Meter, dataGroup);
                }
            }
        }
        private void DetectDisturbances(DataGroup dataGroup, VICycleDataGroup viCycleDataGroup)
        {
            List<Range<int>> aPhaseDisturbanceRanges = DetectDisturbanceRanges(ToPerUnit(viCycleDataGroup.VA?.RMS));
            List<Range<int>> bPhaseDisturbanceRanges = DetectDisturbanceRanges(ToPerUnit(viCycleDataGroup.VB?.RMS));
            List<Range<int>> cPhaseDisturbanceRanges = DetectDisturbanceRanges(ToPerUnit(viCycleDataGroup.VC?.RMS));
            List<Range<int>> abPhaseDisturbanceRanges = DetectDisturbanceRanges(ToPerUnit(viCycleDataGroup.VAB?.RMS));
            List<Range<int>> bcPhaseDisturbanceRanges = DetectDisturbanceRanges(ToPerUnit(viCycleDataGroup.VBC?.RMS));
            List<Range<int>> caPhaseDisturbanceRanges = DetectDisturbanceRanges(ToPerUnit(viCycleDataGroup.VCA?.RMS));

            List<Disturbance> disturbanceList = aPhaseDisturbanceRanges.Select(range => ToDisturbance(viCycleDataGroup.VA?.RMS, range, Phase.AN))
                .Concat(bPhaseDisturbanceRanges.Select(range => ToDisturbance(viCycleDataGroup.VB?.RMS, range, Phase.BN)))
                .Concat(cPhaseDisturbanceRanges.Select(range => ToDisturbance(viCycleDataGroup.VC?.RMS, range, Phase.CN)))
                .Concat(abPhaseDisturbanceRanges.Select(range => ToDisturbance(viCycleDataGroup.VAB?.RMS, range, Phase.AB)))
                .Concat(bcPhaseDisturbanceRanges.Select(range => ToDisturbance(viCycleDataGroup.VBC?.RMS, range, Phase.BC)))
                .Concat(caPhaseDisturbanceRanges.Select(range => ToDisturbance(viCycleDataGroup.VCA?.RMS, range, Phase.CA)))
                .ToList();

            IEnumerable<Range<int>> allDisturbanceRanges = aPhaseDisturbanceRanges
                .Concat(bPhaseDisturbanceRanges)
                .Concat(cPhaseDisturbanceRanges)
                .Concat(abPhaseDisturbanceRanges)
                .Concat(bcPhaseDisturbanceRanges)
                .Concat(caPhaseDisturbanceRanges);

            IEnumerable<Disturbance> worstDisturbances = Range<int>.MergeAllOverlapping(allDisturbanceRanges)
                .Select(range =>
                {
                    Disturbance worst = null;

                    foreach (Disturbance disturbance in disturbanceList.Where(disturbance => ToRange(disturbance).Overlaps(range)))
                    {
                        if ((object)worst == null || m_isMoreSevere(disturbance.PerUnitMagnitude, worst.PerUnitMagnitude))
                            worst = disturbance;
                    }

                    worst = worst.Clone();
                    worst.Phase = Phase.Worst;
                    return worst;
                });

            disturbanceList.AddRange(worstDisturbances);
            m_disturbances.Add(dataGroup, disturbanceList);
        }
        private IEnumerable<COMTRADEChannelData> GetCycleChannelData(VICycleDataGroup cycleDataGroup, IEnumerable<OutputChannel> outputChannels)
        {
            // Create a function to get the load order of a collection of
            // channels where collections should have no more than 1 channel
            Func<IEnumerable<OutputChannel>, int> getLoadOrder = channels => channels
                .Select(channel => channel.LoadOrder)
                .DefaultIfEmpty(int.MaxValue)
                .First();

            // Convert the cycle data set to a collection of cycle data groups
            List<Tuple<string, CycleDataGroup>> cycleDataGroups = new List<Tuple<string, CycleDataGroup>>
            {
                Tuple.Create("VA", cycleDataGroup.VA),
                Tuple.Create("VB", cycleDataGroup.VB),
                Tuple.Create("VC", cycleDataGroup.VC),
                Tuple.Create("IA", cycleDataGroup.IA),
                Tuple.Create("IB", cycleDataGroup.IB),
                Tuple.Create("IC", cycleDataGroup.IC),
                Tuple.Create("IR", cycleDataGroup.IR)
            };

            // Join the output channels to the cycle data groups, order them by LoadOrder, and then
            // return a collection containing only the RMS and Phase series from each cycle data group
            return cycleDataGroups
                .GroupJoin(outputChannels, tuple => tuple.Item1, outputChannel => outputChannel.ChannelKey, (tuple, channels) => new { LoadOrder = getLoadOrder(channels), ChannelKey = tuple.Item1, CycleDataGroup = tuple.Item2 })
                .OrderBy(cycleDataGroupInfo => cycleDataGroupInfo.LoadOrder)
                .ThenBy(cycleDataGroupInfo => cycleDataGroupInfo.ChannelKey)
                .SelectMany((cycleDataGroupInfo, index) => ToAnalogChannelCollection(index, cycleDataGroupInfo.ChannelKey, cycleDataGroupInfo.CycleDataGroup));
        }
        private void WriteResults(MeterDataSet meterDataSet, DataGroup dataGroup, VICycleDataGroup viCycleDataGroup, List<Fault> faults, string resultsFilePath)
        {
            XDocument resultsDocument;
            XElement results;
            string lineName;

            lineName = meterDataSet.Meter.MeterLines
                .Where(ml => ml.LineID == dataGroup.Line.ID)
                .Select(ml => ml.LineName)
                .FirstOrDefault() ?? dataGroup.Line.AssetKey;

            results =
                new XElement("results",
                    new XElement("meter", meterDataSet.Meter.Name),
                    new XElement("disturbanceFiles", GetPathElements(meterDataSet.FileGroup)),
                    new XElement("line",
                        new XElement("name", lineName),
                        new XElement("length", dataGroup.Line.Length.ToString(DoubleFormat))
                    ),
                    new XElement("prefault",
                        new XElement("time", dataGroup.StartTime.ToString(DateTimeFormat)),
                        GetCycleElements(viCycleDataGroup, 0)
                    ),
                    GetFaultElements(faults)
                );

            // Create the XML document
            resultsDocument =
                new XDocument(
                    new XElement("openFLE", results)
                );

            resultsDocument.Save(resultsFilePath);
        }
 private List<XElement> GetCycleElements(VICycleDataGroup viCycleDataGroup, int cycleIndex)
 {
     return new List<XElement>()
     {
         GetCycleElement("VA", viCycleDataGroup.VA, cycleIndex),
         GetCycleElement("VB", viCycleDataGroup.VB, cycleIndex),
         GetCycleElement("VC", viCycleDataGroup.VC, cycleIndex),
         GetCycleElement("IA", viCycleDataGroup.IA, cycleIndex),
         GetCycleElement("IB", viCycleDataGroup.IB, cycleIndex),
         GetCycleElement("IC", viCycleDataGroup.IC, cycleIndex)
     };
 }