233 lines · 12.2 KB · C#
RawDownload
//******************************************************************************************************//  SampleActionAdapter.cs - Gbtc////  Copyright © 2015, Grid Protection Alliance.  All Rights Reserved.////  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See//  the NOTICE file distributed with this work for additional information regarding copyright ownership.//  The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this//  file except in compliance with the License. You may obtain a copy of the License at:////      http://opensource.org/licenses/MIT////  Unless agreed to in writing, the subject software distributed under the License is distributed on an//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the//  License for the specific language governing permissions and limitations.////  Code Modification History://  ----------------------------------------------------------------------------------------------------//  10/06/2015 - J. Ritchie Carroll//       Generated original version of source code.////****************************************************************************************************** using System;using System.Collections.Concurrent;using System.ComponentModel;using System.Collections.Generic;using System.Data;using System.Linq;using GSF;using GSF.Data;using GSF.Diagnostics;using GSF.TimeSeries;using GSF.TimeSeries.Adapters;using GSF.Units;using GSF.Units.EE; // Define PhasorMeasurements as pair of measurement keys representing an angle and a magnitude, i.e., Tuple<MeasurementKey, MeasurementKey>:using PhasorMeasurements = System.Tuple<GSF.TimeSeries.MeasurementKey, GSF.TimeSeries.MeasurementKey>; // Define LineMeasurements as pair of PhasorMeasurements representing measurement keys for a voltage and an associated current phasor:using LineMeasurements = System.Tuple</* PhasorMeasurements, PhasorMeasurements >*/        System.Tuple<GSF.TimeSeries.MeasurementKey, GSF.TimeSeries.MeasurementKey>,         System.Tuple<GSF.TimeSeries.MeasurementKey, GSF.TimeSeries.MeasurementKey>>; namespace TestingAdapters{    /// <summary>    /// Defines a sample action adapter for reference.    /// </summary>    [Description("Sample Action: Example action adapter code")]    class SampleActionAdapter : ActionAdapterBase    {        #region [ Members ]         // Constants        private const double SqrtOf3 = 1.7320508075688772935274463415059D;         // Fields        private LineMeasurements[] m_lineMeasurements;         #endregion         #region [ Properties ]         /// <summary>        /// Gets the flag indicating if this adapter supports temporal processing.        /// </summary>        public override bool SupportsTemporalProcessing        {            get            {                return false;            }        }         /// <summary>        /// Gets or sets an alternate database connection to use to get configuration information.        /// </summary>        [Description(            "Defines the needed parameters for an alternate database connection used to get configuration information. Example: " +            "alternateDatabaseConnection={connectionString={Data Source=localhost\\SQLEXPRESS; Initial Catalog=AltDB; Integrated Security=SSPI}; " +            "dataProviderString={AssemblyName={System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089}; " +            "ConnectionType=System.Data.SqlClient.SqlConnection; AdapterType=System.Data.SqlClient.SqlDataAdapter}}")]        [DefaultValue("")]        public string AlternateDatabaseConnection { get; set;  }         #endregion         #region [ Methods ]         /// <summary>        /// Initializes <see cref="ActionAdapterBase"/>.        /// </summary>        public override void Initialize()        {            base.Initialize();             Dictionary<string, string> settings = Settings;            string alternateDatabaseConnection;            AdoDataConnection connection = null;             try            {                // Load optional parameters                if (settings.TryGetValue("AlternateDatabaseConnection", out alternateDatabaseConnection) && !string.IsNullOrEmpty(alternateDatabaseConnection))                {                    string connectionString, dataProviderString;                    settings = alternateDatabaseConnection.ParseKeyValuePairs();                    settings.TryGetValue("ConnectionString", out connectionString);                    settings.TryGetValue("DataProviderString", out dataProviderString);                     if (!string.IsNullOrEmpty(connectionString) && !string.IsNullOrEmpty(dataProviderString))                        connection = new AdoDataConnection(connectionString, dataProviderString);                }                 // Fall back on current openPDC database if alternate connection was not provided                if ((object)connection == null)                    connection = new AdoDataConnection("systemSettings");                 // This example assumes stored procedure returns a table with a column named ID that is a Guid, each row representing an input measurement                MeasurementKey[] inputKeys = connection.RetrieveData("GetMyInputsProc @param1 @param2", "param1Value", "param2Value").Rows.OfType<DataRow>()                    .Select(row => MeasurementKey.LookUpBySignalID(Guid.Parse(row["ID"].ToString()))).ToArray();                 // Lookup signal types for defined input measurements                SignalType[] inputTypes = inputKeys.Select(LookupSignalType).ToArray();                 // Segregate inputs into voltage and current phasor measurements                MeasurementKey[] voltageAngles = inputKeys.Where((key, index) => inputTypes[index] == SignalType.VPHA).ToArray();                MeasurementKey[] voltageMagnitudes = inputKeys.Where((key, index) => inputTypes[index] == SignalType.VPHM).ToArray();                MeasurementKey[] currentAngles = inputKeys.Where((key, index) => inputTypes[index] == SignalType.IPHA).ToArray();                MeasurementKey[] currentMagnitudes = inputKeys.Where((key, index) => inputTypes[index] == SignalType.IPHM).ToArray();                 // Validate input measurement types have quartic alignment                if (voltageAngles.Length != currentAngles.Length || voltageAngles.Length != voltageMagnitudes.Length || currentAngles.Length != currentMagnitudes.Length)                    throw new InvalidOperationException("A different number of voltage and current phasor input measurement keys were supplied - the current and voltage phasors inputs must be supplied in pairs to represent a line measurement set, i.e., one set of voltage phasor input measurements must be supplied for each current phasor input measurement in a consecutive sequence (e.g., VA1;VM1;IA1;IM1;  VA2;VM2;IA2;IM2; ... VAn;VMn;IAn;IMn)");                 // Reduce inputs to validated set of source measurements                InputMeasurementKeys = voltageAngles.Concat(voltageMagnitudes).Concat(currentAngles).Concat(currentMagnitudes).Distinct().ToArray();                 // Store phasor pairs as line measurements                PhasorMeasurements voltageMeasurements, currentMeasurements;                m_lineMeasurements = new LineMeasurements[voltageAngles.Length];                 // Needed values for a line consist of measurements for voltage phasors and current phasors                for (int i = 0; i < m_lineMeasurements.Length; i++)                {                    voltageMeasurements = new PhasorMeasurements(voltageAngles[i], voltageMagnitudes[i]);                    currentMeasurements = new PhasorMeasurements(currentAngles[i], currentMagnitudes[i]);                    m_lineMeasurements[i] = new LineMeasurements(voltageMeasurements, currentMeasurements);                }                 // Define output measurements as defined in stored procedure                OutputMeasurements = connection.RetrieveData("GetMyOutputsProc @param1 @param2", "param1Value", "param2Value").Rows.OfType<DataRow>()                    .Select(row => new Measurement() { Metadata = MeasurementKey.LookUpBySignalID(Guid.Parse(row["ID"].ToString())).Metadata }).Cast<IMeasurement>().ToArray();            }            finally            {                if ((object)connection != null)                    connection.Dispose();            }        }         /// <summary>        /// Publish <see cref="IFrame"/> of time-aligned collection of <see cref="IMeasurement"/> values that arrived within the        /// concentrator's defined <see cref="ConcentratorBase.LagTime"/>.        /// </summary>        /// <param name="frame"><see cref="IFrame"/> of measurements with the same timestamp that arrived within <see cref="ConcentratorBase.LagTime"/> that are ready for processing.</param>        /// <param name="index">Index of <see cref="IFrame"/> within a second ranging from zero to <c><see cref="ConcentratorBase.FramesPerSecond"/> - 1</c>.</param>        /// <remarks>        /// If user implemented publication function consistently exceeds available publishing time (i.e., <c>1 / <see cref="ConcentratorBase.FramesPerSecond"/></c> seconds),        /// concentration will fall behind. A small amount of this time is required by the <see cref="ConcentratorBase"/> for processing overhead, so actual total time        /// available for user function process will always be slightly less than <c>1 / <see cref="ConcentratorBase.FramesPerSecond"/></c> seconds.        /// </remarks>        protected override void PublishFrame(IFrame frame, int index)        {            ConcurrentDictionary<MeasurementKey, IMeasurement> measurements = frame.Measurements;            PhasorMeasurements voltageMeasurements, currentMeasurements;            IMeasurement voltageAngle, voltageMagnitude, currentAngle, currentMagnitude;            double[] results = new double[OutputMeasurements.Length];             for (int i = 0; i < results.Length; i++)                results[i] = double.NaN;             for (int i = 0; i < m_lineMeasurements.Length; i++)            {                // Get measurement keys for voltage and current phasors                voltageMeasurements = m_lineMeasurements[i].Item1;                currentMeasurements = m_lineMeasurements[i].Item2;                 // Get angle and magnitude values of voltage and current phasors                if (measurements.TryGetValue(voltageMeasurements.Item1, out voltageAngle) &&                     measurements.TryGetValue(voltageMeasurements.Item2, out voltageMagnitude) &&                     measurements.TryGetValue(currentMeasurements.Item1, out currentAngle) &&                    measurements.TryGetValue(currentMeasurements.Item2, out currentMagnitude))                {                    // Do your calculation on measurements (in this example, a rough megawatt calculation)...                    results[i] =                         (SqrtOf3 * voltageMagnitude.AdjustedValue) * currentMagnitude.AdjustedValue *                         Math.Cos(Angle.FromDegrees(currentAngle.AdjustedValue - voltageAngle.AdjustedValue)) / SI.Mega;                }            }             // Publish results            IMeasurement[] outputMeasurements = new IMeasurement[OutputMeasurements.Length];             for (int i = 0; i < outputMeasurements.Length; i++)                outputMeasurements[i] = Measurement.Clone(OutputMeasurements[i], results[i], frame.Timestamp);             OnNewMeasurements(outputMeasurements);        }         // Lookup signal type for given measurement key        private SignalType LookupSignalType(MeasurementKey key)        {            try            {                DataRow[] filteredRows = DataSource.Tables["ActiveMeasurements"].Select($"ID = '{key}'");                 if (filteredRows.Length > 0)                    return (SignalType)Enum.Parse(typeof(SignalType), filteredRows[0]["SignalType"].ToString(), true);            }            catch (Exception ex)            {                OnProcessException(MessageLevel.Warning, new InvalidOperationException($"Failed to lookup signal type for measurement {key}: {ex.Message}", ex));            }             return SignalType.NONE;        }         #endregion    }}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t