/// <summary> /// Parses the file into a meter data set per meter contained in the file. /// </summary> /// <param name="filePath">The path to the file to be parsed.</param> /// <returns>List of meter data sets, one per meter.</returns> public void Parse(string filePath) { DataSourceRecord dataSource = null; ObservationRecord observation; IEnumerable <ChannelInstance> channelInstances; Meter meter = null; Channel channel; DataSeries dataSeries; DateTime[] timeData; while (m_parser.HasNextObservationRecord()) { observation = m_parser.NextObservationRecord(); if ((object)observation.DataSource == null) { continue; } if ((object)dataSource == null) { dataSource = observation.DataSource; meter = ParseDataSource(dataSource); m_meterDataSet.Meter = meter; } if (!AreEquivalent(dataSource, observation.DataSource)) { throw new InvalidDataException($"PQDIF file \"{filePath}\" defines too many data sources."); } channelInstances = observation.ChannelInstances .Where(channelInstance => QuantityType.IsQuantityTypeID(channelInstance.Definition.QuantityTypeID)) .Where(channelInstance => channelInstance.SeriesInstances.Any()) .Where(channelInstance => channelInstance.SeriesInstances[0].Definition.ValueTypeID == SeriesValueType.Time); foreach (ChannelInstance channelInstance in channelInstances) { timeData = ParseTimeData(channelInstance); foreach (SeriesInstance seriesInstance in channelInstance.SeriesInstances.Skip(1)) { channel = ParseSeries(seriesInstance); dataSeries = new DataSeries(); dataSeries.DataPoints = timeData.Zip(ParseValueData(seriesInstance), (time, d) => new DataPoint() { Time = time, Value = d }).ToList(); dataSeries.SeriesInfo = channel.Series[0]; meter.Channels.Add(channel); m_meterDataSet.DataSeries.Add(dataSeries); } } } }
public void Parse(string filePath) { List <DataSourceRecord> dataSources; List <ObservationRecord> observationRecords; List <ChannelInstance> channelInstances; List <SeriesInstance> seriesInstances; List <SeriesDefinition> seriesDefinitions; Meter meter; Channel channel; DataSeries dataSeries; DateTime[] timeData; // Build the list of observation records in the PQDIF file observationRecords = new List <ObservationRecord>(); while (m_parser.HasNextObservationRecord()) { observationRecords.Add(m_parser.NextObservationRecord()); } // Build the list of all data source records in the PQDIF file dataSources = observationRecords .Select(observation => observation.DataSource) .Distinct() .ToList(); // If there are no data sources, there is no // need to go any further because we won't be // able to interpret any of the channel data if (!dataSources.Any()) { return; } // Validate data sources to make sure there is only one data source defined in the file if (!dataSources.Zip(dataSources.Skip(1), (ds1, ds2) => AreEquivalent(ds1, ds2)).All(b => b)) { throw new InvalidDataException($"PQDIF file \"{filePath}\" defines too many data sources."); } // Create a meter from the parsed data source meter = ParseDataSource(dataSources.First()); // Build the list of all channel instances in the PQDIF file channelInstances = observationRecords .SelectMany(observation => observation.ChannelInstances) .Where(channelInstance => QuantityType.IsQuantityTypeID(channelInstance.Definition.QuantityTypeID)) .Where(channelInstance => channelInstance.SeriesInstances.Any()) .Where(channelInstance => channelInstance.SeriesInstances[0].Definition.ValueTypeID == SeriesValueType.Time) .ToList(); // Create the list of series instances so we can // build it as we process each channel instance seriesInstances = new List <SeriesInstance>(); Dictionary <Channel, DataSeries> startChannelsAndDataSeries = new Dictionary <Channel, DataSeries>(); Dictionary <Channel, DataSeries> endChannelsAndDataSeries = new Dictionary <Channel, DataSeries>(); foreach (ChannelInstance channelInstance in channelInstances) { bool timeValueChannel = channelInstance.Definition.QuantityTypeID == QuantityType.WaveForm || channelInstance.Definition.QuantityTypeID == QuantityType.ValueLog || channelInstance.Definition.QuantityTypeID == QuantityType.Phasor || channelInstance.Definition.QuantityTypeID == QuantityType.Flash || channelInstance.Definition.QuantityTypeID == QuantityType.MagDurTime || channelInstance.Definition.QuantityTypeID == QuantityType.MagDurCount; // TODO: Create representation for quantity types that do not define time/value data if (!timeValueChannel) { continue; } // Parse time data from the channel instance timeData = ParseTimeData(channelInstance); foreach (SeriesInstance seriesInstance in channelInstance.SeriesInstances.Skip(1)) { // Create a channel from the parsed series instance seriesInstances.Add(seriesInstance); channel = ParseSeries(seriesInstance); // Parse the values and zip them with time data to create data points dataSeries = new DataSeries(); dataSeries.DataPoints = timeData.Zip(ParseValueData(seriesInstance), (time, d) => new DataPoint() { Time = time, Value = d }).ToList(); dataSeries.SeriesInfo = channel.Series[0]; // Add the new channel to the meter's channel list if (channel.Name.ToLower().Contains("start")) { startChannelsAndDataSeries[channel] = dataSeries; } else if (channel.Name.ToLower().Contains("end")) { endChannelsAndDataSeries[channel] = dataSeries; } else { channel.Meter = meter; meter.Channels.Add(channel); m_meterDataSet.DataSeries.Add(dataSeries); } } } foreach (Channel chan in startChannelsAndDataSeries.Keys) { string baseChannelName = chan.Name.ToLower().Replace("start", ""); Channel endChannel = endChannelsAndDataSeries.Keys.Where(ch => ch.Name.ToLower().Replace("end", "") == baseChannelName).FirstOrDefault(); if ((object)endChannel != null) { Channel combinedChannel = chan; DataSeries combinedDataSeries = startChannelsAndDataSeries[chan]; // Replace "Start" in combinedChannel.Name with "Start + End"; int index = combinedChannel.Name.IndexOf("start", StringComparison.OrdinalIgnoreCase); combinedChannel.Name = combinedChannel.Name.Remove(index, 5).Insert(index, "Start + End"); combinedDataSeries.DataPoints.AddRange(endChannelsAndDataSeries[endChannel].DataPoints); combinedChannel.Meter = meter; meter.Channels.Add(combinedChannel); m_meterDataSet.DataSeries.Add(combinedDataSeries); } } // Build a list of series definitions that were not instanced by this PQDIF file seriesDefinitions = dataSources .SelectMany(dataSource => dataSource.ChannelDefinitions) .SelectMany(channelDefinition => channelDefinition.SeriesDefinitions) .Distinct() .Except(seriesInstances.Select(seriesInstance => seriesInstance.Definition)) .ToList(); // Add each of the series definitions which were not instanced to the meter's list of channels foreach (SeriesDefinition seriesDefinition in seriesDefinitions) { meter.Channels.Add(ParseSeries(seriesDefinition)); } m_meterDataSet.Meter = meter; }
/// <summary> /// Parses the file into a meter data set per meter contained in the file. /// </summary> /// <param name="filePath">The path to the file to be parsed.</param> /// <returns>List of meter data sets, one per meter.</returns> public void Parse(string filePath) { List <DataSourceRecord> dataSources; List <ObservationRecord> observationRecords; List <ChannelInstance> channelInstances; List <SeriesInstance> seriesInstances; List <SeriesDefinition> seriesDefinitions; Meter meter; Channel channel; DataSeries dataSeries; DateTime[] timeData; // Build the list of observation records in the PQDIF file observationRecords = new List <ObservationRecord>(); while (m_parser.HasNextObservationRecord()) { observationRecords.Add(m_parser.NextObservationRecord()); } // Build the list of all data source records in the PQDIF file dataSources = observationRecords .Select(observation => observation.DataSource) .Distinct() .ToList(); // If there are no data sources, there is no // need to go any further because we won't be // able to interpret any of the channel data if (!dataSources.Any()) { return; } // Validate data sources to make sure there is only one data source defined in the file if (!dataSources.Zip(dataSources.Skip(1), (ds1, ds2) => AreEquivalent(ds1, ds2)).All(b => b)) { throw new InvalidDataException($"PQDIF file \"{filePath}\" defines too many data sources."); } // Create a meter from the parsed data source meter = ParseDataSource(dataSources.First()); m_meterDataSet.Meter = meter; // Build the list of all channel instances in the PQDIF file channelInstances = observationRecords .SelectMany(observation => observation.ChannelInstances) .Where(channelInstance => QuantityType.IsQuantityTypeID(channelInstance.Definition.QuantityTypeID)) .Where(channelInstance => channelInstance.SeriesInstances.Any()) .Where(channelInstance => channelInstance.SeriesInstances[0].Definition.ValueTypeID == SeriesValueType.Time) .ToList(); // Create the list of series instances so we can // build it as we process each channel instance seriesInstances = new List <SeriesInstance>(); foreach (ChannelInstance channelInstance in channelInstances) { bool timeValueChannel = channelInstance.Definition.QuantityTypeID == QuantityType.WaveForm || channelInstance.Definition.QuantityTypeID == QuantityType.ValueLog || channelInstance.Definition.QuantityTypeID == QuantityType.Phasor || channelInstance.Definition.QuantityTypeID == QuantityType.Flash || channelInstance.Definition.QuantityTypeID == QuantityType.MagDurTime || channelInstance.Definition.QuantityTypeID == QuantityType.MagDurCount; // TODO: Create representation for quantity types that do not define time/value data if (!timeValueChannel) { continue; } // Parse time data from the channel instance timeData = ParseTimeData(channelInstance); foreach (SeriesInstance seriesInstance in channelInstance.SeriesInstances.Skip(1)) { // Create a channel from the parsed series instance seriesInstances.Add(seriesInstance); channel = ParseSeries(seriesInstance); // Parse the values and zip them with time data to create data points dataSeries = new DataSeries(); dataSeries.DataPoints = timeData.Zip(ParseValueData(seriesInstance), (time, d) => new DataPoint() { Time = time, Value = d }).ToList(); dataSeries.SeriesInfo = channel.Series[0]; // Add the new channel to the meter's channel list meter.Channels.Add(channel); m_meterDataSet.DataSeries.Add(dataSeries); } } // Build a list of series definitions that were not instanced by this PQDIF file seriesDefinitions = dataSources .SelectMany(dataSource => dataSource.ChannelDefinitions) .SelectMany(channelDefinition => channelDefinition.SeriesDefinitions) .Distinct() .Except(seriesInstances.Select(seriesInstance => seriesInstance.Definition)) .ToList(); // Add each of the series definitions which were not instanced to the meter's list of channels foreach (SeriesDefinition seriesDefinition in seriesDefinitions) { meter.Channels.Add(ParseSeries(seriesDefinition)); } }
/// <summary> /// Parses the file into a meter data set per meter contained in the file. /// </summary> /// <param name="filePath">The path to the file to be parsed.</param> /// <returns>List of meter data sets, one per meter.</returns> public void Parse(string filePath) { List <DataSourceRecord> dataSources; List <ObservationRecord> observationRecords; List <ChannelInstance> channelInstances; List <SeriesInstance> seriesInstances; List <SeriesDefinition> seriesDefinitions; Meter meter; Channel channel; DataSeries dataSeries; DateTime[] timeData; // Build the list of observation records in the PQDIF file observationRecords = new List <ObservationRecord>(); while (m_parser.HasNextObservationRecord()) { observationRecords.Add(m_parser.NextObservationRecord()); } // Build the list of all data source records in the PQDIF file dataSources = observationRecords .Select(observation => observation.DataSource) .Distinct() .ToList(); // If there are no data sources, there is no // need to go any further because we won't be // able to interpret any of the channel data if (!dataSources.Any()) { return; } // Validate data sources to make sure there is only one data source defined in the file if (!dataSources.Zip(dataSources.Skip(1), (ds1, ds2) => AreEquivalent(ds1, ds2)).All(b => b)) { throw new InvalidDataException($"PQDIF file \"{filePath}\" defines too many data sources."); } // Create a meter from the parsed data source meter = ParseDataSource(dataSources.First()); // Build the list of all channel instances in the PQDIF file channelInstances = observationRecords .SelectMany(observation => observation.ChannelInstances) .Where(channelInstance => QuantityType.IsQuantityTypeID(channelInstance.Definition.QuantityTypeID)) .Where(channelInstance => channelInstance.SeriesInstances.Any()) .Where(channelInstance => channelInstance.SeriesInstances[0].Definition.ValueTypeID == SeriesValueType.Time) .ToList(); // Create the list of series instances so we can // build it as we process each channel instance seriesInstances = new List <SeriesInstance>(); foreach (ChannelInstance channelInstance in channelInstances) { bool timeValueChannel = channelInstance.Definition.QuantityTypeID == QuantityType.WaveForm || channelInstance.Definition.QuantityTypeID == QuantityType.ValueLog || channelInstance.Definition.QuantityTypeID == QuantityType.Phasor; if (!timeValueChannel) { continue; } // Parse time data from the channel instance timeData = ParseTimeData(channelInstance, m_systemFrequency); foreach (SeriesInstance seriesInstance in channelInstance.SeriesInstances.Skip(1)) { // Create a channel from the parsed series instance seriesInstances.Add(seriesInstance); channel = ParseSeries(seriesInstance); // Parse the values and zip them with time data to create data points dataSeries = new DataSeries(); dataSeries.DataPoints = timeData.Zip(ParseValueData(seriesInstance), (time, d) => new DataPoint() { Time = time, Value = d }).ToList(); dataSeries.SeriesInfo = channel.Series[0]; // Add the new channel to the meter's channel list channel.Meter = meter; meter.Channels.Add(channel); m_meterDataSet.DataSeries.Add(dataSeries); } } foreach (ChannelInstance channelInstance in channelInstances) { bool magDurChannel = channelInstance.Definition.QuantityTypeID == QuantityType.MagDur || channelInstance.Definition.QuantityTypeID == QuantityType.MagDurCount || channelInstance.Definition.QuantityTypeID == QuantityType.MagDurTime; if (!magDurChannel) { continue; } timeData = channelInstance.SeriesInstances .Where(seriesInstance => seriesInstance.Definition.ValueTypeID == SeriesValueType.Time) .Select(seriesInstance => ParseTimeData(seriesInstance, m_systemFrequency)) .FirstOrDefault(); Guid valType = SeriesValueType.Val; Guid maxType = SeriesValueType.Max; Guid minType = SeriesValueType.Min; Guid avgType = SeriesValueType.Avg; double[] valData = channelInstance.SeriesInstances .Where(seriesInstance => seriesInstance.Definition.ValueTypeID == valType) .Select(seriesInstance => ParseValueData(seriesInstance)) .FirstOrDefault(); double[] maxData = channelInstance.SeriesInstances .Where(seriesInstance => seriesInstance.Definition.ValueTypeID == maxType) .Select(seriesInstance => ParseValueData(seriesInstance)) .FirstOrDefault() ?? valData; double[] minData = channelInstance.SeriesInstances .Where(seriesInstance => seriesInstance.Definition.ValueTypeID == minType) .Select(seriesInstance => ParseValueData(seriesInstance)) .FirstOrDefault() ?? valData; double[] avgData = channelInstance.SeriesInstances .Where(seriesInstance => seriesInstance.Definition.ValueTypeID == avgType) .Select(seriesInstance => ParseValueData(seriesInstance)) .FirstOrDefault() ?? valData; TimeSpan[] durData = channelInstance.SeriesInstances .Where(seriesInstance => seriesInstance.Definition.ValueTypeID == SeriesValueType.Duration) .Select(seriesInstance => ParseTimeSpanData(seriesInstance, m_systemFrequency)) .FirstOrDefault(); int minLength = Common.Min(timeData.Length, maxData.Length, minData.Length, avgData.Length, durData.Length); QuantityUnits units = channelInstance.SeriesInstances .Where(seriesInstance => new[] { valType, maxType, minType, avgType }.Contains(seriesInstance.Definition.ValueTypeID)) .Select(seriesInstance => seriesInstance.Definition.QuantityUnits) .FirstOrDefault(); for (int i = 0; i < minLength; i++) { DateTime time = ((object)timeData != null) ? timeData[i] : channelInstance.ObservationRecord.StartTime; double max = maxData[i]; double min = minData[i]; double avg = avgData[i]; TimeSpan dur = durData[i]; m_meterDataSet.ReportedDisturbances.Add(new ReportedDisturbance(channelInstance.Definition.Phase, time, max, min, avg, dur, units)); } } // Build a list of series definitions that were not instanced by this PQDIF file seriesDefinitions = dataSources .SelectMany(dataSource => dataSource.ChannelDefinitions) .SelectMany(channelDefinition => channelDefinition.SeriesDefinitions) .Distinct() .Except(seriesInstances.Select(seriesInstance => seriesInstance.Definition)) .ToList(); // Add each of the series definitions which were not instanced to the meter's list of channels foreach (SeriesDefinition seriesDefinition in seriesDefinitions) { meter.Channels.Add(ParseSeries(seriesDefinition)); } m_meterDataSet.Meter = meter; // Parse triggers from PQube data m_meterDataSet.Triggers = PQubeReader.GetTriggers(observationRecords); }