/// <summary> /// Run calculations for specific time stamps. /// </summary> /// inspired from: /// <see cref="https://pisquare.osisoft.com/message/28537#28537"/> /// <param name="analysis">Analysis that needs to be evaluated</param> /// <param name="times">List of times</param> /// <param name="evaluationTime">output, contains the time taken to execute all the calculations</param> /// <param name="evaluationsErrorsCount">output, contains the number of evaluations in error.</param> /// <returns></returns> public List <AFValue> Run(AFAnalysis analysis, IEnumerable <AFTime> times, out TimeSpan evaluationTime, out int evaluationsErrorsCount) { evaluationsErrorsCount = 0; var results = new List <AFValue>(); var stopwatch = Stopwatch.StartNew(); var analysisConfiguration = analysis.AnalysisRule.GetConfiguration(); var state = new AFAnalysisRuleState(analysisConfiguration); foreach (var time in times) { // Console.WriteLine("Evaluating for {0}", time); state.Reset(); state.SetExecutionTimeAndPopulateInputs(time); analysis.AnalysisRule.Run(state); if (state.EvaluationError != null) { if (_debug) { _logger.ErrorFormat("Analyse in error at time: {3:s} - {0} - at {1}, Error: {2}", analysis.Name, analysis.GetPath(), state.EvaluationError, time); } evaluationsErrorsCount += 1; } // this merges the state (results) with the configuration so its easier to loop with both... var resultSet = analysisConfiguration.ResolvedOutputs.Zip(state.Outputs, Tuple.Create); foreach (var result in resultSet) { // for more clarty, we take out our data into clearer variables AFAnalysisRuleResolvedOutput analysisRow = result.Item1; var calcRes = (AFValue)result.Item2; // we filter to get only the results that have an output attribute ( an AFValue ) if (analysisRow.Attribute != null) { // add new AF Value into the results table results.Add(new AFValue((AFAttribute)analysisRow.Attribute, calcRes.Value, calcRes.Timestamp)); } } } stopwatch.Stop(); evaluationTime = stopwatch.Elapsed; return(results); }
public void Run(AFTimeRange timeRange) { if (!TryValidate()) { Console.WriteLine("Failed to evaluate '{0}' due to configuration errors.", _analysis.GetPath()); return; } var eventProvider = GetEventProvider(); var state = new AFAnalysisRuleState(_configuration); var outputHandler = new OutputHandler(_configuration); foreach (var time in eventProvider.GetEvents(timeRange)) { Console.WriteLine("Evaluating for {0}", time); state.Reset(); state.SetExecutionTimeAndPopulateInputs(time); _analysis.AnalysisRule.Run(state); Exception evaluationError = state.EvaluationError; if (!ReferenceEquals(evaluationError, null)) { AFAnalysisException analysisException = evaluationError as AFAnalysisException; if (ReferenceEquals(analysisException, null) || analysisException.Severity == AFAnalysisErrorSeverity.Error) { // This is something for which Analysis service would stop running the analysis Console.WriteLine("Fatal error: {0}", state.EvaluationError.Message); break; } else { // Non-fatal error with severity < Error; analysis would continue to run Console.WriteLine("Warning: {0}", state.EvaluationError.Message); } } else { outputHandler.ProcessOutputs(state); foreach (var output in _configuration.ResolvedOutputs.Zip(state.Outputs, Tuple.Create)) { Console.WriteLine("\t{0} = {1}", output.Item1.DisplayName, output.Item2); } } } outputHandler.Flush(); }
/// <summary> /// Adapted from Mike's example /// Mike also talks about errors and warnings in his post, you should check it. /// </summary> /// <see cref="https://pisquare.osisoft.com/message/28537#28537"/> /// <param name="analysis"></param> /// <param name="times"></param> /// <returns></returns> private static List <AFValue> Calculate(AFAnalysis analysis, IEnumerable <AFTime> times) { var results = new List <AFValue>(); var analysisConfiguration = analysis.AnalysisRule.GetConfiguration(); var state = new AFAnalysisRuleState(analysisConfiguration); foreach (var time in times) { //Console.WriteLine("Evaluating for {0}", time); state.Reset(); state.SetExecutionTimeAndPopulateInputs(time); analysis.AnalysisRule.Run(state); if (state.EvaluationError == null) { // this merges the state (results) with the configuration so its easier to loop with both... var resultSet = analysisConfiguration.ResolvedOutputs.Zip(state.Outputs, Tuple.Create); foreach (var result in resultSet) { // for more clarty, we take out our data into clearer variables AFAnalysisRuleResolvedOutput analysisRow = result.Item1; var calcRes = (AFValue)result.Item2; // we filter to get only the results that have an output attribute ( an AFValue ) if (analysisRow.Attribute != null) { // add new AF Value into the results table results.Add(new AFValue((AFAttribute)analysisRow.Attribute, calcRes.Value, calcRes.Timestamp)); } } } else { // errors occur quite frequently, for example, TagTot('attr1', 't', '*') will fail if computed at '*' = 't' // but this does not occur when the analysis is running on event base. //Console.WriteLine("An error occurred: {0}", state.EvaluationError.Message); } } return(results); }