diff --git a/Source/Libraries/Adapters/DataQualityMonitoring/StateFlagsTransferAdapter.cs b/Source/Libraries/Adapters/DataQualityMonitoring/StateFlagsTransferAdapter.cs
index 774ca2a916..86a09fba66 100644
--- a/Source/Libraries/Adapters/DataQualityMonitoring/StateFlagsTransferAdapter.cs
+++ b/Source/Libraries/Adapters/DataQualityMonitoring/StateFlagsTransferAdapter.cs
@@ -52,6 +52,11 @@ public class StateFlagsTransferAdapter : FilterAdapterBase
///
public const bool DefaultSupportsTemporalProcessing = false;
+ ///
+ /// Default value for the property.
+ ///
+ public const int DefaultExecutionOrder = 0;
+
// Fields
private MeasurementStateFlags m_flags;
private MeasurementKey[] m_sourceMeasurements;
@@ -63,78 +68,64 @@ public class StateFlagsTransferAdapter : FilterAdapterBase
#endregion
- #region [ Constructors ]
-
- #endregion
-
#region [ Properties ]
///
- /// Gets or sets the collection of measurements from which state will be transfered.
+ /// Gets or sets the collection of measurements from which state will be transferred.
///
- [ConnectionStringParameter,
- Description("Defines the collection of measurements from which state will be transfered.")]
+ [ConnectionStringParameter]
+ [Description("Defines the collection of measurements from which state will be transfered.")]
public MeasurementKey[] SourceMeasurements
{
- get
- {
- return m_sourceMeasurements;
- }
- set
- {
- m_sourceMeasurements = value;
- }
+ get => m_sourceMeasurements;
+ set => m_sourceMeasurements = value;
}
///
/// Gets or sets the collection of measurements to which state will be transferred.
///
- [ConnectionStringParameter,
- Description("Defines the collection of measurements to which state will be transferred.")]
+ [ConnectionStringParameter]
+ [Description("Defines the collection of measurements to which state will be transferred.")]
public MeasurementKey[] DestinationMeasurements
{
- get
- {
- return m_destinationMeasurements;
- }
- set
- {
- m_destinationMeasurements = value;
- }
+ get => m_destinationMeasurements;
+ set => m_destinationMeasurements = value;
+ }
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)] // Overriden to hide from UI
+ public override MeasurementKey[] InputMeasurementKeys
+ {
+ get => base.InputMeasurementKeys;
+ set => base.InputMeasurementKeys = value;
}
///
- /// Gets or sets the flags to be transfered from source
+ /// Gets or sets the flags to be transferred from source
/// measurements to the corresponding destination measurements.
///
- [ConnectionStringParameter,
- DefaultValue(DefaultFlags),
- Description("Defines the set of flags to be transfered.")]
+ [ConnectionStringParameter]
+ [DefaultValue(DefaultFlags)]
+ [Description("Defines the set of flags to be transferred.")]
public MeasurementStateFlags Flags
{
- get
- {
- return m_flags;
- }
- set
- {
- m_flags = value;
- }
+ get => m_flags;
+ set => m_flags = value;
}
+ ///
+ [ConnectionStringParameter]
+ [Description("Defines the value that determines the order in which filter adapters are executed.")]
+ [DefaultValue(DefaultExecutionOrder)]
+ public override int ExecutionOrder { get; set; }
+
///
/// Gets the flag indicating if this adapter supports temporal processing.
///
- [ConnectionStringParameter,
- Description("Define the flag indicating if this adapter supports temporal processing."),
- DefaultValue(DefaultSupportsTemporalProcessing)]
- public override bool SupportsTemporalProcessing
- {
- get
- {
- return m_supportsTemporalProcessing;
- }
- }
+ [ConnectionStringParameter]
+ [Description("Define the flag indicating if this adapter supports temporal processing.")]
+ [DefaultValue(DefaultSupportsTemporalProcessing)]
+ public override bool SupportsTemporalProcessing => m_supportsTemporalProcessing;
#endregion
@@ -155,15 +146,15 @@ public override void Initialize()
if (settings.TryGetValue(nameof(SourceMeasurements), out setting))
m_sourceMeasurements = ParseInputMeasurementKeys(DataSource, true, setting);
else
- throw new ArgumentException("Missing required connection string parameter: SourceMeasurements", nameof(SourceMeasurements));
+ throw new ArgumentException("Missing required connection string parameter", nameof(SourceMeasurements));
if (settings.TryGetValue(nameof(DestinationMeasurements), out setting))
m_destinationMeasurements = ParseInputMeasurementKeys(DataSource, true, setting);
else
- throw new ArgumentException("Missing required connection string parameter: DestinationMeasurements", nameof(DestinationMeasurements));
+ throw new ArgumentException("Missing required connection string parameter", nameof(DestinationMeasurements));
if (m_sourceMeasurements.Length != m_destinationMeasurements.Length)
- throw new ArgumentException($"Source and destination measurements are parallel arrays, therefore their lengths must match - Src: {m_sourceMeasurements.Length}, Dst: {m_destinationMeasurements.Length}");
+ throw new ArgumentException($"Source and destination measurements are parallel arrays, therefore their lengths must match - Src: {m_sourceMeasurements.Length:N0}, Dst: {m_destinationMeasurements.Length:N0}");
InputMeasurementKeys = m_sourceMeasurements.Concat(m_destinationMeasurements).ToArray();
@@ -182,10 +173,9 @@ public override void Initialize()
if (!settings.TryGetValue(nameof(Flags), out setting) || !Enum.TryParse(setting, out m_flags))
m_flags = DefaultFlags;
- if (settings.TryGetValue(nameof(SupportsTemporalProcessing), out setting))
- m_supportsTemporalProcessing = setting.ParseBoolean();
- else
- m_supportsTemporalProcessing = DefaultSupportsTemporalProcessing;
+ ExecutionOrder = settings.TryGetValue(nameof(ExecutionOrder), out setting) && int.TryParse(setting, out int executionOrder) ? executionOrder : DefaultExecutionOrder;
+
+ m_supportsTemporalProcessing = settings.TryGetValue(nameof(SupportsTemporalProcessing), out setting) && setting.ParseBoolean();
}
///
diff --git a/Source/Libraries/Adapters/DynamicCalculator/DynamicFilter.cs b/Source/Libraries/Adapters/DynamicCalculator/DynamicFilter.cs
index c8d2f3366e..c3928d4590 100644
--- a/Source/Libraries/Adapters/DynamicCalculator/DynamicFilter.cs
+++ b/Source/Libraries/Adapters/DynamicCalculator/DynamicFilter.cs
@@ -54,7 +54,13 @@ public enum FilterOperation
/// Defines filter operation that changes measurement values based on expression evaluation.
///
[Description("Changes measurement values based on expression evaluation.")]
- ValueAugmentation
+ ValueAugmentation,
+
+ ///
+ /// Sets measurement state flags when expression evaluates to true.
+ ///
+ [Description("Sets measurement state flags when expression evaluates to true.")]
+ SetFlagsWhenTrue
}
///
@@ -88,6 +94,7 @@ public class DynamicFilter : DynamicCalculator, IFilterAdapter
private long m_processedMeasurements;
private long m_removedMeasurements;
private long m_skippedRemovalSets;
+ private long m_measurementFlagsAssigned;
private bool m_valueIsArray;
private int m_valueArrayLength;
private object m_result;
@@ -157,10 +164,15 @@ public DynamicFilter() =>
public FilterOperation FilterOperation { get; set; } = DefaultFilterOperation;
///
- /// Gets or sets measurement state flags that are applied when a value has been replaced when filter operation is set to .
+ /// Gets or sets measurement state flags that are applied when a value has been replaced when filter operation is set to
+ /// or when flags are set when filter operation is set to .
///
[ConnectionStringParameter]
- [Description("Defines measurement state flags that are applied when a value has been replaced when filter operation is set to value augmentation.")]
+ [Description
+ (
+ $"Defines measurement state flags that are applied when a value has been replaced when filter operation is set to '{nameof(FilterOperation.ValueAugmentation)}' " +
+ $"or when flags are set when filter operation is set to '{nameof(FilterOperation.SetFlagsWhenTrue)}'."
+ )]
[DefaultValue(DefaultAugmentationFlags)]
public MeasurementStateFlags AugmentationFlags { get; set; } = DefaultAugmentationFlags;
@@ -208,7 +220,7 @@ public override IMeasurement[] OutputMeasurements // Redeclared to hide property
}
///
- /// Gets or sets the allowed past time deviation tolerance, in seconds (can be sub-second).
+ /// Gets or sets the allowed past-time deviation tolerance, in seconds (can be sub-second).
///
[EditorBrowsable(EditorBrowsableState.Never)]
public new double LagTime // Redeclared to hide property - not relevant to this adapter
@@ -301,16 +313,22 @@ public override string Status
status.AppendLine($" Filter Operation: {FilterOperation}");
status.AppendLine($" Target Value Type: {(m_valueIsArray ? "Array" : "Singleton")}");
- if (FilterOperation == FilterOperation.RemoveWhenTrue)
+ switch (FilterOperation)
{
- status.AppendLine($" Processed Measurements: {m_processedMeasurements:N0}");
- status.AppendLine($" Removed Measurements: {m_removedMeasurements:N0}");
- status.AppendLine($" Skipped Removal Sets: {m_skippedRemovalSets:N0}");
- }
- else
- {
- status.AppendLine($" Augmentation Flags: {AugmentationFlags}");
- status.AppendLine($" Augmented Measurements: {m_processedMeasurements:N0}");
+ case FilterOperation.RemoveWhenTrue:
+ status.AppendLine($" Processed Measurements: {m_processedMeasurements:N0}");
+ status.AppendLine($" Removed Measurements: {m_removedMeasurements:N0}");
+ status.AppendLine($" Skipped Removal Sets: {m_skippedRemovalSets:N0}");
+ break;
+ case FilterOperation.ValueAugmentation:
+ status.AppendLine($" Augmentation Flags: {AugmentationFlags}");
+ status.AppendLine($" Augmented Measurements: {m_processedMeasurements:N0}");
+ break;
+ case FilterOperation.SetFlagsWhenTrue:
+ status.AppendLine($" Augmentation Flags: {AugmentationFlags}");
+ status.AppendLine($" Processed Measurements: {m_processedMeasurements:N0}");
+ status.AppendLine($"Measurement Flags Assigned: {m_measurementFlagsAssigned:N0}");
+ break;
}
return status.ToString();
@@ -402,11 +420,9 @@ public void HandleNewMeasurements(ICollection measurements)
Interlocked.Increment(ref m_skippedRemovalSets);
return;
}
- else
- {
- int index = 0;
- indexes = measurements.ToDictionary(measurement => measurement.Key, _ => index++);
- }
+
+ int index = 0;
+ indexes = measurements.ToDictionary(measurement => measurement.Key, _ => index++);
}
void removeMeasurements(List indexesToBeRemoved)
@@ -446,12 +462,18 @@ void removeMeasurements(List indexesToBeRemoved)
case FilterOperation.ValueAugmentation when m_valueIsArray:
ProcessValueAugmentationForArray(inputs);
break;
+ case FilterOperation.SetFlagsWhenTrue when m_valueIsArray:
+ ProcessSetFlagsWhenTrueForArray(inputs);
+ break;
case FilterOperation.RemoveWhenTrue when !m_valueIsArray:
removeMeasurements(ProcessRemoveWhenTrueForSingleton(inputs, indexes));
break;
case FilterOperation.ValueAugmentation when !m_valueIsArray:
ProcessValueAugmentationForSingleton(inputs);
break;
+ case FilterOperation.SetFlagsWhenTrue when !m_valueIsArray:
+ ProcessSetFlagsWhenTrueForSingleton(inputs);
+ break;
default:
if (m_processedMeasurements == 0L)
OnStatusMessage(MessageLevel.Warning, $"Filter operation \"{FilterOperation}\" is not supported by the {nameof(DynamicFilter)} \"{Name}\".");
@@ -500,6 +522,29 @@ private void ProcessValueAugmentationForArray(IReadOnlyDictionary inputs)
+ {
+ long measurementFlagsAssigned = 0L;
+
+ for (m_index = 0; m_index < m_valueArrayLength; m_index++)
+ {
+ if (!inputs.TryGetValue(m_variableKeys[$"value[{m_index}]"], out IMeasurement measurement))
+ continue;
+
+ Calculate(inputs, new Dictionary { ["value"] = m_index });
+
+ // If calculation result is true, we update measurement flags
+ if (!m_result.ToString().ParseBoolean())
+ continue;
+
+ measurement.StateFlags |= AugmentationFlags;
+ measurementFlagsAssigned++;
+ }
+
+ Interlocked.Add(ref m_measurementFlagsAssigned, measurementFlagsAssigned);
+ }
+
[MethodImpl(MethodImplOptions.Synchronized)] // Access to expression context and m_result requires synchronization
private List ProcessRemoveWhenTrueForSingleton(IReadOnlyDictionary inputs, IReadOnlyDictionary indexes)
{
@@ -533,6 +578,22 @@ private void ProcessValueAugmentationForSingleton(IReadOnlyDictionary inputs)
+ {
+ if (!inputs.TryGetValue(m_variableKeys["value"], out IMeasurement measurement))
+ return;
+
+ Calculate(inputs);
+
+ // If calculation result is true, we update measurement flags
+ if (!m_result.ToString().ParseBoolean())
+ return;
+
+ measurement.StateFlags |= AugmentationFlags;
+ Interlocked.Increment(ref m_measurementFlagsAssigned);
+ }
+
///
/// Handler for assignment of special variables, e.g., constants, for the .
///