/// <summary> /// Gets the first block of the load profile data /// </summary> /// <param name="actualLimitingTable">The actual limiting table that applies to the data set</param> /// <param name="statusTable">The status table that applies to the data set</param> /// <param name="dataSetTable">The data set</param> /// <param name="setStatus">The status record for the data set at the time of the read</param> /// <returns>The first block of Load Profile Data</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 10/07/08 RCG 2.00.00 N/A Created // 12/12/11 RCG 2.53.20 Modified for Extended LP and IP support private LPBlockDataRecord GetFirstBlock(StdTable61 actualLimitingTable, StdTable63 statusTable, StdTable64 dataSetTable, out LPSetStatusRecord setStatus) { LPBlockDataRecord FirstBlock = null; LPSetActualLimits SetLimits = actualLimitingTable.GetSetLimits(dataSetTable.DataSet); LPSetStatusRecord SetStatusBeforeRead = null; LPSetStatusRecord SetStatusAfterRead = null; int BlockReadRetries = 0; ushort FirsBlockIndex = 0; do { SetStatusBeforeRead = statusTable.GetSetStatusRecord(dataSetTable.DataSet); if (SetStatusBeforeRead.DataListType == LPSetStatusRecord.ListType.Circular) { FirsBlockIndex = (ushort)((SetStatusBeforeRead.LastBlockElement + 1) % SetStatusBeforeRead.NumberOfValidBlocks); } if (SetStatusBeforeRead.NumberOfValidBlocks > 1) { FirstBlock = ReadLPBlock(dataSetTable, FirsBlockIndex, SetLimits.IntervalsPerBlock); } else { // The first block is the last block so we need to use the number of valid intervals FirstBlock = ReadLPBlock(dataSetTable, FirsBlockIndex, SetStatusBeforeRead.NumberOfValidIntervals); } SetStatusAfterRead = statusTable.GetSetStatusRecord(dataSetTable.DataSet); }while (BlockReadRetries < LP_READ_RETRIES && HasLastBlockRolledOver(SetStatusBeforeRead, SetStatusAfterRead)); setStatus = SetStatusAfterRead; return(FirstBlock); }
/// <summary> /// Determines the relative index of the block that contains the start date specified. /// </summary> /// <param name="setLimits">The actual limits for the data set.</param> /// <param name="setStatus">The status of the data set when last block was read.</param> /// <param name="firstBlock">The last block in the data set.</param> /// <param name="startDate">The start date that is being searched for.</param> /// <returns>The relative index of the block that contains the start date.</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 10/08/08 RCG 2.00.00 N/A Created private int DetermineStartBlockIndex(LPSetActualLimits setLimits, LPSetStatusRecord setStatus, LPBlockDataRecord firstBlock, DateTime startDate) { int StartBlockIndex = 0; bool IncludeFirstBlock; IncludeFirstBlock = startDate <= firstBlock.BlockEndTime; if (!IncludeFirstBlock) { // We need to determine the starting block for (int iBlock = 1; iBlock < setStatus.NumberOfValidBlocks; iBlock++) { DateTime BlockEndTime = (DateTime)firstBlock.BlockEndTime; BlockEndTime = BlockEndTime.AddMinutes(iBlock * setLimits.IntervalsPerBlock * setLimits.IntervalLength); if (BlockEndTime >= startDate) { StartBlockIndex = iBlock; break; } } } else { StartBlockIndex = 0; } return(StartBlockIndex); }
/// <summary> /// Get the all of the Profile Data from the specified set of tables /// </summary> /// <param name="actualLimitingTable">The actual limiting table for the data set</param> /// <param name="controlTable">The control table for the data set</param> /// <param name="statusTable">The status table for the data set</param> /// <param name="dataSetTable">The data set table for the data set</param> /// <returns>The profile data that has been read.</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 12/06/11 RCG 2.53.20 N/A Created // 06/15/12 jrf 2.60.32 199972 Adding logging statements to help debug issue next time we see it. // protected LoadProfileData GetProfileData(StdTable61 actualLimitingTable, StdTable62 controlTable, StdTable63 statusTable, StdTable64 dataSetTable) { LoadProfileData LPData = null; LPSetActualLimits SetLimits = actualLimitingTable.GetSetLimits(dataSetTable.DataSet); LPSetDataSelection SetDataSelection = controlTable.GetDataSelection(dataSetTable.DataSet); LPBlockDataRecord[] Blocks; LPBlockDataRecord FirstBlock; LPBlockDataRecord LastBlock; LPSetStatusRecord SetStatus; ushort NumberOfBlocks; ushort FirstBlockIndex; m_Logger.WriteLine(Logger.LoggingLevel.Functional, "Getting Profile Data"); SetStatus = statusTable.GetSetStatusRecord(dataSetTable.DataSet); m_Logger.WriteLine(Logger.LoggingLevel.Detailed, "Number of Blocks: " + SetStatus.NumberOfValidBlocks.ToString(CultureInfo.InvariantCulture)); m_Logger.WriteLine(Logger.LoggingLevel.Detailed, "Number of Intervals: " + SetStatus.NumberOfValidIntervals.ToString(CultureInfo.InvariantCulture)); if (SetStatus.NumberOfValidBlocks > 0 && SetStatus.NumberOfValidIntervals > 0) { OnShowProgress(new ShowProgressEventArgs(1, SetStatus.NumberOfValidBlocks, "Reading Load Profile data...", "Reading Load Profile data...")); // Read the first and last blocks GetFirstAndLastBlock(actualLimitingTable, statusTable, dataSetTable, out FirstBlock, out LastBlock, out SetStatus); // Read the rest of the blocks using the last block status NumberOfBlocks = SetStatus.NumberOfValidBlocks; Blocks = new LPBlockDataRecord[NumberOfBlocks]; Blocks[0] = FirstBlock; if (NumberOfBlocks > 1) { Blocks[NumberOfBlocks - 1] = LastBlock; FirstBlockIndex = (ushort)((SetStatus.LastBlockElement + 1) % NumberOfBlocks); for (ushort RelativeBlockIndex = 1; RelativeBlockIndex < NumberOfBlocks - 1; RelativeBlockIndex++) { ushort ActualBlockIndex = (ushort)((FirstBlockIndex + RelativeBlockIndex) % NumberOfBlocks); m_Logger.WriteLine(Logger.LoggingLevel.Detailed, "Reading Block # " + ActualBlockIndex.ToString(CultureInfo.InvariantCulture)); Blocks[RelativeBlockIndex] = ReadLPBlock(dataSetTable, ActualBlockIndex, SetLimits.IntervalsPerBlock); OnStepProgress(new ProgressEventArgs()); } } OnHideProgress(new EventArgs()); // Create the LoadProfileData object. LPData = CreateLoadProfileDataObject(Blocks, SetLimits, SetDataSelection); } return(LPData); }
/// <summary> /// Adds the channels to the LoadProfilData object. /// </summary> /// <param name="loadProfileData">The LoadProfileData object to add the channels to.</param> /// <param name="setLimits">The set limits for the data set</param> /// <param name="setDataSelection">The data selection for the data set</param> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 10/03/08 RCG 2.00.00 N/A Created // 12/12/11 RCG 2.53.20 Modified for Extended LP and IP support private void AddChannels(ref LoadProfileData loadProfileData, LPSetActualLimits setLimits, LPSetDataSelection setDataSelection) { List <string> ChannelNames = DetermineChannelNames(setDataSelection); List <float> PulseWeights = DeterminePulseWeights(setLimits, setDataSelection); for (int iChannel = 0; iChannel < setLimits.NumberOfChannels; iChannel++) { loadProfileData.AddChannel(ChannelNames[iChannel], PulseWeights[iChannel], 1.0f); } }
/// <summary> /// Determines the relative index of the block that contains the end date specified. /// </summary> /// <param name="setLimits">The actual limits for the data set.</param> /// <param name="setStatus">The status of the data set when last block was read.</param> /// <param name="lastBlock">The last block in the data set.</param> /// <param name="endDate">The end date that is being searched for.</param> /// <returns>The relative index of the block that contains the end time.</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 10/08/08 RCG 2.00.00 N/A Created // 09/22/09 AF 2.30.02 Corrected the equation for determining last block private int DetermineEndBlockIndex(LPSetActualLimits setLimits, LPSetStatusRecord setStatus, LPBlockDataRecord lastBlock, DateTime endDate) { int EndBlockIndex = 0; DateTime LastBlockStartTime; bool IncludeLastBlock; LastBlockStartTime = DetermineIntervalTime(lastBlock, 0, setLimits.IntervalLength); if (lastBlock.Intervals.Length > 1) { LastBlockStartTime = AdjustTimeForDST(LastBlockStartTime, lastBlock.Intervals[0], lastBlock.Intervals[1], lastBlock.Intervals[setStatus.NumberOfValidIntervals - 1]); } IncludeLastBlock = endDate >= LastBlockStartTime; if (!IncludeLastBlock) { // We need to determine the last block. Start at the next to last block for (int iBlock = setStatus.NumberOfValidBlocks - 2; iBlock >= 1; iBlock--) { DateTime BlockStartTime = LastBlockStartTime; BlockStartTime = BlockStartTime.AddMinutes(-1 * (setStatus.NumberOfValidBlocks - (iBlock + 1)) * setLimits.IntervalsPerBlock * setLimits.IntervalLength); if (BlockStartTime <= endDate) { EndBlockIndex = iBlock; break; } } } else { EndBlockIndex = setStatus.NumberOfValidBlocks - 1; } return(EndBlockIndex); }
/// <summary> /// Determines the pulse weights for each channel. /// </summary> /// <param name="setLimits">The set limits for the data set</param> /// <param name="setDataSelection">The data selection for the data set</param> /// <returns>The list of pulse weights.</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 10/03/08 RCG 2.00.00 N/A Created // 12/12/11 RCG 2.53.20 Modified for Extended LP and IP support private List <float> DeterminePulseWeights(LPSetActualLimits setLimits, LPSetDataSelection setDataSelection) { List <float> PulseWeights = new List <float>(); if (setDataSelection != null && setLimits.IncludeScalarDivisor) { // We have all the data we need to determine the pulse weights for (int iChannel = 0; iChannel < setLimits.NumberOfChannels; iChannel++) { // Make sure that we get a float value. PulseWeights.Add((float)setDataSelection.Scalars[iChannel] / (float)setDataSelection.Divisors[iChannel]); } } else { // We don't have the data we need so just use 1.0 so that the raw data is used. for (int iChannel = 0; iChannel < setLimits.NumberOfChannels; iChannel++) { PulseWeights.Add(1.0f); } } return(PulseWeights); }
/// <summary> /// Creates the LoadProfileData object from the specified blocks. /// </summary> /// <param name="loadProfileBlocks">The list of blocks to use to create the object ordered by date.</param> /// <param name="setLimits">The set limits for the data set</param> /// <param name="setDataSelection">The data selection for the data set</param> /// <returns>The LoadProfileData object.</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 10/03/08 RCG 2.00.00 N/A Created // 12/12/11 RCG 2.53.20 Modified for Extended LP and IP support private LoadProfileData CreateLoadProfileDataObject(LPBlockDataRecord[] loadProfileBlocks, LPSetActualLimits setLimits, LPSetDataSelection setDataSelection) { LoadProfileData LPData = new LoadProfilePulseData(setLimits.IntervalLength); AddChannels(ref LPData, setLimits, setDataSelection); AddIntervals(ref LPData, loadProfileBlocks); return(LPData); }
/// <summary> /// Gets the load profile data between the specified dates. /// </summary> /// <param name="startDate">The start date of the load profile data to get.</param> /// <param name="endDate">The end date of the load profile data to get.</param> /// <param name="actualLimitingTable">The actual limiting table for the data set</param> /// <param name="controlTable">The control table for the data set</param> /// <param name="statusTable">The status table for the data set</param> /// <param name="dataSetTable">The data set table for the data set</param> /// <returns>The load profile data from the dates specified.</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 12/06/11 RCG 2.53.20 N/A Created public LoadProfileData GetProfileData(DateTime startDate, DateTime endDate, StdTable61 actualLimitingTable, StdTable62 controlTable, StdTable63 statusTable, StdTable64 dataSetTable) { LPSetActualLimits SetLimits = actualLimitingTable.GetSetLimits(dataSetTable.DataSet); LPBlockDataRecord FirstBlock; LPBlockDataRecord LastBlock; LPBlockDataRecord[] Blocks; LPSetStatusRecord SetStatus; LoadProfileData LPData = null; int StartBlockIndex; int EndBlockIndex; int FirstBlockIndex; SetStatus = statusTable.GetSetStatusRecord(dataSetTable.DataSet); if (SetStatus != null) { if (SetStatus.NumberOfValidBlocks > 1 && SetStatus.NumberOfValidIntervals > 0) { OnShowProgress(new ShowProgressEventArgs(1, 2, "Determining blocks to read...", "Determining blocks to read...")); // Get the first and last blocks in order to determine the blocks we need to read. GetFirstAndLastBlock(actualLimitingTable, statusTable, dataSetTable, out FirstBlock, out LastBlock, out SetStatus); OnStepProgress(new ProgressEventArgs()); // Determine which blocks to read StartBlockIndex = DetermineStartBlockIndex(SetLimits, SetStatus, FirstBlock, startDate); EndBlockIndex = DetermineEndBlockIndex(SetLimits, SetStatus, LastBlock, endDate); Blocks = new LPBlockDataRecord[EndBlockIndex - StartBlockIndex + 1]; FirstBlockIndex = (SetStatus.LastBlockElement + 1) % SetStatus.NumberOfValidBlocks; OnHideProgress(new EventArgs()); OnShowProgress(new ShowProgressEventArgs(1, EndBlockIndex - StartBlockIndex, "Reading Load Profile data...", "Reading Load Profile data...")); // Read the blocks for (int RelativeBlockIndex = StartBlockIndex; RelativeBlockIndex <= EndBlockIndex; RelativeBlockIndex++) { int BlockArrayIndex = RelativeBlockIndex - StartBlockIndex; OnStepProgress(new ProgressEventArgs()); // We already have the first and last blocks so just add those if included. if (RelativeBlockIndex == 0) { Blocks[BlockArrayIndex] = FirstBlock; } else if (RelativeBlockIndex == SetStatus.NumberOfValidBlocks - 1) { // The last block Blocks[BlockArrayIndex] = LastBlock; } else { // We need to read the block ushort ActualBlockIndex = (ushort)((FirstBlockIndex + RelativeBlockIndex) % SetStatus.NumberOfValidBlocks); Blocks[BlockArrayIndex] = ReadLPBlock(dataSetTable, ActualBlockIndex, SetLimits.IntervalsPerBlock); } } OnStepProgress(new ProgressEventArgs("Creating Load Profile object...")); // Create the LoadProfileData object. LPData = CreateLoadProfileDataObject(Blocks, SetLimits, controlTable.GetDataSelection(dataSetTable.DataSet)); OnStepProgress(new ProgressEventArgs("Removing additional intervals...")); // Trim out intervals that were not requested. LPData.Intervals.RemoveAll(delegate(LPInterval interval) { return(interval.Time < startDate || interval.Time > endDate); }); OnHideProgress(new EventArgs()); } else if (SetStatus.NumberOfValidBlocks == 1) { OnShowProgress(new ShowProgressEventArgs(1, 3, "Reading Load Profile data...", "Reading Load Profile data...")); // Just get the first block the trim will take care of anything outside the range FirstBlock = GetFirstBlock(actualLimitingTable, statusTable, dataSetTable, out SetStatus); OnStepProgress(new ProgressEventArgs()); LPData = CreateLoadProfileDataObject(new LPBlockDataRecord[] { FirstBlock }, SetLimits, controlTable.GetDataSelection(dataSetTable.DataSet)); OnStepProgress(new ProgressEventArgs()); // Trim out intervals that were not requested. LPData.Intervals.RemoveAll(delegate(LPInterval interval) { return(interval.Time < startDate || interval.Time > endDate); }); OnStepProgress(new ProgressEventArgs()); OnHideProgress(new EventArgs()); } } return(LPData); }
/// <summary> /// Reads the table from the meter. /// </summary> /// <returns>The PSEM result from the read.</returns> // Revision History // MM/DD/YY who Version Issue# Description // -------- --- ------- ------ --------------------------------------- // 10/02/06 RCG 7.40.00 N/A Created // 12/12/11 RCG 2.53.20 Modified for Extended LP and IP support public override PSEMResponse Read() { m_Logger.WriteLine(Logger.LoggingLevel.Detailed, "Table " + m_TableID.ToString(CultureInfo.InvariantCulture) + " Read"); // Read the table PSEMResponse Result = base.Read(); m_DataStream.Position = 0; if (Result == PSEMResponse.Ok) { m_uiMemoryLength = m_Reader.ReadUInt32(); m_usFlags = m_Reader.ReadUInt16(); // The MFG tables add an extra byte for UINT24 and INT24 data types so we need to combine both bytes m_UsedFormats = (LPDataFormats)((ushort)m_Reader.ReadByte() | ((ushort)m_Reader.ReadByte() << 8)); if (m_Table0.IsTableUsed(MapLPSetToTable(LPDataSet.Set1)) == true) { m_Set1ActualLimits = new LPSetActualLimits(); m_Set1ActualLimits.Parse(m_Reader); m_Set1ActualLimits.InhibitOverflow = InhibitSet1Overflow; m_Set1ActualLimits.IncludeScalarDivisor = IncludeSet1ScalarDivisor; } else { m_Set1ActualLimits = null; } if (m_Table0.IsTableUsed(MapLPSetToTable(LPDataSet.Set2)) == true) { m_Set2ActualLimits = new LPSetActualLimits(); m_Set2ActualLimits.Parse(m_Reader); m_Set2ActualLimits.InhibitOverflow = InhibitSet2Overflow; m_Set2ActualLimits.IncludeScalarDivisor = IncludeSet2ScalarDivisor; } else { m_Set2ActualLimits = null; } if (m_Table0.IsTableUsed(MapLPSetToTable(LPDataSet.Set3)) == true) { m_Set3ActualLimits = new LPSetActualLimits(); m_Set3ActualLimits.Parse(m_Reader); m_Set3ActualLimits.InhibitOverflow = InhibitSet3Overflow; m_Set3ActualLimits.IncludeScalarDivisor = IncludeSet3ScalarDivisor; } else { m_Set3ActualLimits = null; } if (m_Table0.IsTableUsed(MapLPSetToTable(LPDataSet.Set4)) == true) { m_Set4ActualLimits = new LPSetActualLimits(); m_Set4ActualLimits.Parse(m_Reader); m_Set4ActualLimits.InhibitOverflow = InhibitSet4Overflow; m_Set4ActualLimits.IncludeScalarDivisor = IncludeSet4ScalarDivisor; } else { m_Set4ActualLimits = null; } m_TableState = TableState.Loaded; } return(Result); }