26 Replies Latest reply on Apr 12, 2016 1:31 AM by Mike Zboray

    Get Results from Analysis without defining an Output Attribute

    wpurrer

      Hello,

       

      I'm currently trying to get results from a Analysis with C#. I can access the analysis but calling the "GetResults" function doesnt give me any AFValues as a result. I tried running the analysis before, adding a Case and setting the Target, but nothing seems to work. Is there some kind of documentation or code example i can take a look at, on how to get the results from an analysis? Is it possible without defing an Output Attribute?

        • Re: Get Results from Analysis without defining an Output Attribute
          xwang

          Hi,

           

          I do not think there could be no output attribute for one Analysis.  If create one analysis from PSE, it could automatically create a attribute if do not give an existed one.  Could you please try to create one attribute for your analysis, and read the value from this attribute instead of use "GetResults" from the analysis itselft at first please?

           

          Xi Wang

           

          vCampus team

            • Re: Get Results from Analysis without defining an Output Attribute
              wpurrer

              Thank you for your quick response.

               

              Unfortunately, this is not what i want to do. I want to read the results (multiple ones, not only a single one) directly from the Analysis itself. The PSE has a function where i can preview the results, which gives me a table of all results within a certain time. This is the data i would like to read and get into my C# program, without any attributes.

               

              Is there a possibility to retrieve this "previewed" data?

                • Re: Get Results from Analysis without defining an Output Attribute
                  Rhys Kirk

                  Hey Wolfgang. You can certainly get the values of the variables even if they don't have an output attribute defined...to get a table of previewed events I think you just need to iterate through a list of AFTime for your required time range; I don't remember seeing a bulk call in this respect.

                   

                  Anyway some code:

                   

                   

                   
                  OSIsoft.AF.Analysis.AFAnalysisRuleState rs = new OSIsoft.AF.Analysis.AFAnalysisRuleState(myAnalysis.AnalysisRule);
                  
                  rs.SetExecutionTimeAndPopulateInputs(new AFTime("*"));
                  
                  myAnalysis.AnalysisRule.Run(rs);
                  

                   Note, the "Outputs" property of the AFAnalysisRuleState object has the evaluated calculation values in order that the variables are defined in the Analysis Rule. So, you need to know the index of the variable you want to know about and then retrieve the value from that index position of the Outputs collection. I remember trying to use the AFAnalysisRuleVariableDefinitions class but it didn't seem to be working - or I was doing something wrong.

                   

                  Anyway, hope this helps.

                  1 of 1 people found this helpful
                    • Re: Get Results from Analysis without defining an Output Attribute
                      wpurrer

                      Thank you very much Rhys, this is totally the answer i was looking for! Everythings working as intended!

                        • Re: Get Results from Analysis without defining an Output Attribute
                          Mike Zboray

                          Wolfgang,

                           

                          Rhys's sample is completely correct for a single evaluation, however you are likely to want to call this in a loop for several times. In this case it is recommended that you reuse the AFAnalysisRuleState and use the Reset method to clear out some of the internal state. The analysis rule can store some private data on the state object and use this in later evaluations. This is used in various situations where the past state is important, e.g. Event Frame generation and TimeTrue.

                           

                          Here is a slightly more complete example: 

                           

                                  private static void Run(AFAnalysis analysis, IEnumerable<AFTime> times)
                                  {
                                      var configuration = analysis.AnalysisRule.GetConfiguration();
                                      var state = new AFAnalysisRuleState(configuration);
                                      foreach (var time in times)
                                      {
                                          Console.WriteLine("Evaluating for {0}", time);
                                          state.Reset();
                                          state.SetExecutionTimeAndPopulateInputs(time);
                                          analysis.AnalysisRule.Run(state);
                                          if (state.EvaluationError == null)
                                          {
                                              foreach (var output in configuration.ResolvedOutputs.Zip(state.Outputs, Tuple.Create))
                                              {
                                                  Console.WriteLine("\t{0} = {1}", output.Item1.DisplayName, output.Item2);
                                              }
                                          }
                                          else
                                          {
                                              Console.WriteLine("An error occurred: {0}", state.EvaluationError.Message);
                                          }
                                      }
                                  }
                          

                          There are several methods/objects related to getting metadata about the analysis rule's configuration. They are on AFAnalysisRule: GetVariableDefinitions, GetConfiguration, and the VariableMap property. A summary of the logical flow is that an AnalysisRule will define whatever inputs and outputs it has and you can retrieve them in GetVariableDefinitions (gets an AFAnalysisRuleVariableDefinitions). The VariableMap allows you to direct these inputs and outputs to specific attributes (or in the case of a Rollup, search criteria). The AFAnalysisRuleConfiguration (obtained from GetConfiguration) takes the AFAnalysisRuleVariableDefinitions and the VariableMap and combines them and determines if any inputs/outputs are still outstanding and will report any errors in the configuration. If you wanted to do some more complete error/warning reporting it would look like this:

                           

                                      var configuration = analysis.AnalysisRule.GetConfiguration();
                                      if (configuration.HasExceptions)
                                      {
                                          var exceptionGroups = configuration.ConfigurationExceptions.ToLookup(ex => ex.Severity);
                                          Console.WriteLine("Configuration warnings: {0}", exceptionGroups[AFAnalysisErrorSeverity.Warning].Count());
                                          foreach (var warning in exceptionGroups[AFAnalysisErrorSeverity.Warning])
                                          {
                                              Console.WriteLine("\t{0}", warning.Message);
                                          }
                          
                                          // warnings mean ok to run, but something may not work quite as expected.
                          
                                          int errorCount = exceptionGroups[AFAnalysisErrorSeverity.Error].Count();
                                          Console.WriteLine("Configuration errors: {0}", errorCount);
                                          foreach (var error in exceptionGroups[AFAnalysisErrorSeverity.Error])
                                          {
                                              Console.WriteLine("\t{0}", error.Message);
                                          }
                          
                                          // can't run if there are errors.
                                          if (errorCount > 0)
                                              return;
                                      }
                          

                           

                          NOTE: This works only for the basic scenario where input and output attributes are different. If the analysis reads an attribute and write back to the same attribute, the code is somewhat more involved because you will be required to populate the AnalysisRuleState inputs manually.

                           

                          Mike

                          1 of 1 people found this helpful
                            • Re: Get Results from Analysis without defining an Output Attribute
                              Rhys Kirk

                              Thanks for the more thorough code sample Mike, your code trumps mine.

                                • Re: Get Results from Analysis without defining an Output Attribute
                                  wpurrer

                                  Thanks Mike! I already figured out how to get multiple Results using a loop, but your code looks definetely better ;)

                                    • Re: Get Results from Analysis without defining an Output Attribute
                                      wpurrer

                                      Everything works fine now, but i still got a short question: When the analysis scheduling is set to event-triggered, is there a possibility to get the Input Tags that the analysis triggers on?

                                        • Re: Get Results from Analysis without defining an Output Attribute
                                          Marcos Vainer Loeff

                                          Hello Wolfgang,

                                           


                                          I have just published a new blog post about “Creating and viewing Asset-based analytics programmatically” to which you should refer. It shows how to get access to the ConfigString property of the TimeRule of the AFAnalysis object. On the blog post, I have used the TimeRulePlugIns["Periodic"] plugin. After changing this setting on the PI System Explorer in order to use the TimeRulePlugIns["Natural"] plugin and answer your question, the value of the TimeRule.ConfigString was empty to my surprise.

                                           


                                          Then, I have created another analysis using two attributes (Pressure and Temperatue) on the PE expression but I have only selected the pressure attribute to trigger the calculation. After running my console application again described on the blog post, the value of the TimeRule.ConfigString was “Pressure”.

                                           


                                          My conclusion is that if the TimeRulePlugIns["Natural"] is the plugin used on the analysis, it will result:

                                           

                                          • Empty string: if any input/attribute could trigger the calculation
                                          • A string with only the names of the attributes which could trigger the calculation separated by semicolon. In this case, not all the attributes are able to trigger the calculation.

                                           

                                          Hope this helps you!

                                            • Re: Get Results from Analysis without defining an Output Attribute
                                              wpurrer

                                              Hello Marcos,

                                               

                                              thank your for your reply.

                                               

                                              Unfortunately, adding a second attribute and deselecting one of them to get the input is not an option for me, as i want all inputs that can trigger the calculation, even if there's only one. Is this a bug or is the config string supposed to be empty when all inputs can trigger the calculation?

                                               

                                              Well, an option would be to read the Inputs from the Analysis.AnalysisRule String if the config string is empty. I think this should do the trick aswell.

                                                • Re: Get Results from Analysis without defining an Output Attribute
                                                  Marcos Vainer Loeff

                                                  Hello Wolfgang,

                                                   

                                                  I think that this is the expected behavior. The developers can fix me if I am wrong. I know that you are able to get all the attributes used on the expression after processing the string AnalysisRule.ConfigString which requires some work. But I couldn’t find a method that returns all the attributes used on the PE expressions of the analysis. I will contact some developers to make sure what I wrote in this post is correct.

                                                      • Re: Get Results from Analysis without defining an Output Attribute
                                                        Mike Zboray

                                                        Wolfgang,

                                                         

                                                        Getting the data exactly as the time rule does is somewhat involved. There is a public method on the Natural time rule class that is not exposed via the time rule public interface called GetTriggeringInputs that uses the time rule's configuration to get the input attribute that will actually trigger calculations. Here is an extended example that evaluates data based on the input time stamps:

                                                         

                                                            class Program
                                                            {
                                                                private static readonly bool UseInputData = true;
                                                                private static string dbPath = @"\\testafserver\testdb";
                                                                private static string piServer = "testpiserver";
                                                                private static Func<AFTimeRule, AFAnalysisRuleConfiguration, IEnumerable<IAFAttribute>> GetTriggeringInputs;
                                                        
                                                                static void Main(string[] args)
                                                                {
                                                                    // create an element with an attribute and an analysis
                                                                    var db = (AFDatabase)AFObject.FindObject(dbPath);
                                                        
                                                                    GetTriggeringInputs = GetGetTriggeringInputs(db.PISystem);
                                                        
                                                                    var target = db.Elements.Add("element*");
                                                                    var attribute = target.Attributes.Add("sinusoidatt");
                                                                    attribute.DataReferencePlugIn = db.PISystem.DataReferencePlugIns["PI Point"];
                                                                    attribute.DataReference.ConfigString = string.Format(@"\\{0}\sinusoid", piServer);
                                                                    var analysis = target.Analyses.Add("equation*");
                                                                    analysis.AnalysisRulePlugIn = db.PISystem.AnalysisRulePlugIns["PerformanceEquation"];
                                                                    analysis.AnalysisRule.ConfigString = "a := TagVal('sinusoidatt'); b := Pow(a, 2);";
                                                                    analysis.TimeRulePlugIn = db.PISystem.TimeRulePlugIns["Natural"];
                                                                    // db.CheckIn(); // not need but you can check-in in case you want to view it in PSE.
                                                        
                                                                    var range = new AFTimeRange("*-1d", "*");
                                                                    var configuration = analysis.AnalysisRule.GetConfiguration();
                                                        
                                                                    CheckForErrors(configuration);
                                                        
                                                                    IEnumerable<AFTime> times;
                                                                    if (UseInputData && analysis.TimeRule.Name == "Natural")
                                                                    {
                                                                        times = ByData(range, analysis.TimeRule, configuration);
                                                                    }
                                                                    else
                                                                    {
                                                                        times = ByInterval(range, TimeSpan.FromMinutes(1));
                                                                    }
                                                                    Run(analysis, configuration, times);
                                                                }
                                                        
                                                                // Loads method for querying whether an input can be triggered on that is specific to Natural time rule.
                                                                private static Func<AFTimeRule, AFAnalysisRuleConfiguration, IEnumerable<IAFAttribute>> GetGetTriggeringInputs(PISystem system)
                                                                {
                                                                    var plugin = system.TimeRulePlugIns["Natural"];
                                                                    if (plugin == null)
                                                                        throw new ArgumentException(string.Format("No 'Natural' time rule registered on the PI System '{0}'", system));
                                                        
                                                                    var method = plugin.GetPlugInType().GetMethods(BindingFlags.Public | BindingFlags.Static).FirstOrDefault(m => m.Name == "GetTriggeringInputs" && m.GetParameters().Length == 2);
                                                                    if (method == null)
                                                                        throw new ArgumentException(string.Format("Version {0} of 'Natural' time rule does not support GetTriggeringInputs.", plugin.Version));
                                                        
                                                                    return (Func<AFTimeRule, AFAnalysisRuleConfiguration, IEnumerable<IAFAttribute>>)Delegate.CreateDelegate(typeof(Func<AFTimeRule, AFAnalysisRuleConfiguration, IEnumerable<IAFAttribute>>), method);
                                                                }
                                                        
                                                                private static void CheckForErrors(AFAnalysisRuleConfiguration configuration)
                                                                {
                                                                    if (configuration.HasExceptions)
                                                                    {
                                                                        var exceptionGroups = configuration.ConfigurationExceptions.ToLookup(ex => ex.Severity);
                                                                        Console.WriteLine("Configuration warnings: {0}", exceptionGroups[AFAnalysisErrorSeverity.Warning].Count());
                                                                        foreach (var warning in exceptionGroups[AFAnalysisErrorSeverity.Warning])
                                                                        {
                                                                            Console.WriteLine("\t{0}", warning.Message);
                                                                        }
                                                        
                                                                        // warnings mean ok to run, but something may not work quite as expected.
                                                        
                                                                        int errorCount = exceptionGroups[AFAnalysisErrorSeverity.Error].Count();
                                                                        Console.WriteLine("Configuration errors: {0}", errorCount);
                                                                        foreach (var error in exceptionGroups[AFAnalysisErrorSeverity.Error])
                                                                        {
                                                                            Console.WriteLine("\t{0}", error.Message);
                                                                        }
                                                        
                                                                        // can't run if there are errors.
                                                                        if (errorCount > 0)
                                                                        {
                                                                            Environment.Exit(0);
                                                                        }
                                                                    }
                                                                }
                                                        
                                                                // Get timestamps for evaluation using the input data. Ideally, we could cache this and use the values in evaluation.
                                                                private static IEnumerable<AFTime> ByData(AFTimeRange range, AFTimeRule timeRule, AFAnalysisRuleConfiguration configuration)
                                                                {
                                                                    var times = new SortedSet<AFTime>();
                                                                    var triggeringInputs = GetTriggeringInputs(timeRule, configuration).OfType<AFAttribute>();
                                                                    foreach (var input in triggeringInputs)
                                                                    {
                                                                        AFValues values;
                                                                        if ((input.SupportedDataMethods & AFDataMethods.RecordedValues) == AFDataMethods.RecordedValues)
                                                                        {
                                                                            values = input.Data.RecordedValues(range, AFBoundaryType.Inside, null, null, true);
                                                                        }
                                                                        else
                                                                        {
                                                                            values = input.GetValues(range, 0, null);
                                                                        }
                                                        
                                                                        foreach (var value in values)
                                                                        {
                                                                            times.Add(value.Timestamp);
                                                                        }
                                                                    }
                                                                    return times;
                                                                }
                                                        
                                                                // Generate a sequence of evenly spaced timestamps.
                                                                private static IEnumerable<AFTime> ByInterval(AFTimeRange range, TimeSpan intervalSize)
                                                                {
                                                                    var time = range.StartTime;
                                                                    while (time <= range.EndTime)
                                                                    {
                                                                        yield return time;
                                                                        time = time + intervalSize;
                                                                    }
                                                                }
                                                        
                                                                // Run the analysis at the given times. Output the results to the console.
                                                                private static void Run(AFAnalysis analysis, AFAnalysisRuleConfiguration configuration, IEnumerable<AFTime> times)
                                                                {           
                                                                    var state = new AFAnalysisRuleState(configuration);
                                                                    foreach (var time in times)
                                                                    {
                                                                        Console.WriteLine("Evaluating for {0}", time);
                                                        
                                                                        state.Reset();
                                                                        state.SetExecutionTimeAndPopulateInputs(time);
                                                        
                                                                        foreach (var input in configuration.ResolvedInputs.Zip(state.Inputs, Tuple.Create))
                                                                        {
                                                                            Console.WriteLine("\t{0} = {1}", input.Item1.DisplayName, input.Item2);
                                                                        }
                                                        
                                                                        analysis.AnalysisRule.Run(state);
                                                                        if (state.EvaluationError == null)
                                                                        {
                                                                            foreach (var output in configuration.ResolvedOutputs.Zip(state.Outputs, Tuple.Create))
                                                                            {
                                                                                Console.WriteLine("\t{0} = {1}", output.Item1.DisplayName, output.Item2);
                                                                            }
                                                                        }
                                                                        else
                                                                        {
                                                                            Console.WriteLine("An error occurred: {0}", state.EvaluationError.Message);
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        

                                                         

                                                        NOTE: This works only for the basic scenario where input and output attributes are different. If the analysis reads an attribute and write back to the same attribute, the code is somewhat more involved because you will be required to populate the AnalysisRuleState inputs manually.

                                                         

                                                        Let me know if there are any other questions.

                                                         

                                                        Mike

                                                          • Re: Get Results from Analysis without defining an Output Attribute
                                                            AndrewdJ

                                                            Hi Guys

                                                             

                                                            Which libraries should I be referencing? I can't find the "AFAnalysisRule.GetConfiguration()" method, nor the OSIsoft.AF.Analysis.AFAnalysisRuleState class.

                                                             

                                                             

                                                             

                                                             

                                                             
                                                                        AFAnalysis analysis = afNoti.Analysis;
                                                                        
                                                                        AFAnalysisRule rule = analysis.AnalysisRule;
                                                                        AFAnalysisRules rules = rule.AnalysisRules ;
                                                            
                                                                        var configuration = analysis.AnalysisRule.GetConfiguration();   // ? Where is GetConfiguration? 
                                                            
                                                                        OSIsoft.AF.Analysis.AFAnalysisRuleState ggg = new OSIsoft.AF.Analysis.AFAnalysisRuleState();    // ? Where is AFAnalysisRuleState? 
                                                            

                                                             

                                                             

                                                            My Project type is C# .Net4.0

                                                             

                                                            OSISoft.AFSDK v2.5.1.5159 (C:\Program Files\PIPC\AF\PublicAssemblies\4.0\OSIsoft.AFSDK.dll)

                                                             

                                                            Other libraries referenced:

                                                             

                                                            OSISoft.PIAnalytics.Common v2.0.50727

                                                             

                                                            OSIsoft.PIAnalytics.PerformanceEquation v2.0.50727

                                                             

                                                            OSIsoft.PIAnalytics.SDK v2.0.50727

                                                             

                                                             

                                                             

                                                            What I'm attempting to do is evaluate the each AFAnalysisRule within  an AndCondition AFAnalysisRule. What I'm failing to do is evaluate the "Comparison" rule. The PerformanceEquation Rules are easy to evaluate using the OSIsoft.AN.PerformanceEquation.ANPerformanceEquation().Evaluate()

                                                             

                                                             

                                                             

                                                            regards,

                                                             

                                                            Andrew

                                                              • Re: Get Results from Analysis without defining an Output Attribute
                                                                Mike Zboray

                                                                Andrew,

                                                                 

                                                                These types/methods were added in AF 2.6 to support Abacus. Previously, you could run analysis rules, but there was no way to separate them from their inputs and outputs. This changed so that we could hit the performance goals for Abacus, as well as provide new features like the Preview window in the PSE.

                                                                 

                                                                You will need to install AF 2.6 (client and server) as well as the Analysis Service (it provides the analysis rule plugins which implement the new methods) to use these features.

                                                                 

                                                                After that, only AF SDK is needed. Those assemblies you mentioned are for PI Notifications' SDK.

                                                                 

                                                                Mike

                                                                  • Re: Get Results from Analysis without defining an Output Attribute
                                                                    AndrewdJ

                                                                    Thanks Mike

                                                                     

                                                                    Is there any way to evaluate a Notification's 'Comparison' AFAnalysisRule in the PIAnalytics libraries? (I should perhaps start a new thread for PIAnalytics)

                                                                     

                                                                    I see we can't/shouldn't upgrade to AF2.6 because of the identified issues

                                                                     

                                                                     

                                                                     

                                                                    regards,

                                                                     

                                                                    Andrew

                                                                      • Re: Get Results from Analysis without defining an Output Attribute
                                                                        Mike Zboray

                                                                        Andrew,

                                                                         

                                                                        Running a Notification's analysis rules can be done through the legacy Run/AFCase API. This is a simulation of how the notifications scheduler does it:

                                                                         
                                                                            class Program
                                                                            {
                                                                                static void Main(string[] args)
                                                                                {
                                                                                    var notification = (AFNotification)AFObject.FindObject(@"\\PIANO-CURRENT\Database1\Element1\Notifications[New Notification1]");
                                                                                    if (!notification.Analysis.IsConfigured)
                                                                                    {
                                                                                        string component = notification.Analysis.AnalysisRule.IsConfigured ? "Time Rule" : "Analysis Rule";
                                                                                        Console.WriteLine("Analysis is not configured. {0} is not configured.", component);
                                                                                        Environment.Exit(0);
                                                                                    }
                                                                                    var trEvent = new AFTimeRuleEvent(AFTime.Now, AFTime.Now);
                                                                                    var afCase = new AFCase(notification.Analysis, trEvent);
                                                                                    bool success = afCase.Run();
                                                                        
                                                                                    if (!success)
                                                                                    {
                                                                                        Console.WriteLine("Run failed.");
                                                                                        afCase.Delete();
                                                                                        afCase.ApplyChanges();
                                                                                        Environment.Exit(0);
                                                                                    }
                                                                                    else
                                                                                    {
                                                                                        Console.WriteLine("Run succeeded.");
                                                                                        foreach(var result in afCase.Results)
                                                                                        {
                                                                                            Console.WriteLine("{0}: {1}", result.Attribute, result.Value);
                                                                                        }
                                                                                    }
                                                                                }
                                                                            }
                                                                        

                                                                        I have to say we haven't heavily tested this for the "Preview" scenario, so this might do something unexpected in some cases. In particular, the TimeTrue conditions may depend on a specific amount of time passing. We've tested the new API heavily for this use case because it is used in Analysis Preview (which is similar to backfilling by the service), but because there is no similar functionality in Notifications, I'm not sure how this will hold up.

                                                                         

                                                                        Mike

                                                                    • Re: Get Results from Analysis without defining an Output Attribute

                                                                      Hello Andrew,

                                                                       

                                                                      AFAnalysisRule.GetConfiguration() is not implemented with AF SDK 2.5. You need a reference to AF SDK 2.6.0.5843 (or greater). This library is installed with PI Asset Framework (AF) Client 2014, the updated help comes with PI AF Developer Tools 2014.

                                                                      • Re: Get Results from Analysis without defining an Output Attribute
                                                                        Marcos Vainer Loeff

                                                                        Hello Andrew,

                                                                         

                                                                        In order to be able to use PI Asset Based Analytics features through PI AF SDK, you need to upgrade to version 2.6 (2014). Please download the new version from the vCampus Download Center.

                                                      • Re: Get Results from Analysis without defining an Output Attribute
                                                        kuehcj

                                                        Hello Mike,

                                                        May I know if there is any way that we can evaluate the analysis rules over a list of AFTime instead of evaluating it using one AFTime at a time over a for loop? For example, in the code below, I am hoping that we can pass a list of AFTime to the sub SetExecutionTimeAndPopulateInputs, and when the Run function is called, it will then return the evaluation results over the given AFTimes.

                                                         

                                                        state.SetExecutionTimeAndPopulateInputs(time); 

                                                        analysis.AnalysisRule.Run(state); 

                                                         

                                                        I have looked around in AFSDK documentation, but couldn't find such function. So I just want to confirm with you to make sure that I didn't miss anything.

                                                         

                                                        Thank you.

                                                          • Re: Get Results from Analysis without defining an Output Attribute
                                                            Mike Zboray

                                                            There is no such convenience method in the AFSDK. You have to do what I've shown in the first example. Note that this assumes that the analysis has no dependencies on other analyses and does not use the same attribute for both input and output.

                                                            • Re: Get Results from Analysis without defining an Output Attribute
                                                              skwan

                                                              Hi Chia:

                                                              Analysis Service was designed to be an online calculation engine triggering based on new inputs or based on a clock.  It was never built to be an adhoc calculation engine, which is what it appears you're trying to do.  Having said that, have you considered using something like DataLink to do what you need?  With DataLink, you can use the "Expression" feature to apply Performance Equation functions to your PI data.  Do you think that would solve your needs?

                                                              --

                                                              Steve Kwan

                                                                • Re: Get Results from Analysis without defining an Output Attribute
                                                                  kuehcj

                                                                  Hi Mike & Steve,

                                                                  Thank you for your prompt response. The reason why I asked for the function is not so much just for convenience but practicality.

                                                                  For your info, we have set up standard templates to do analyses calculation and there are hundreds of such elements using these templates. Sometimes users may have made adjustments to certain inputs (such as limit or target which will affect the output of the calculation) and need the whole thing to be recalculated to reflect the correct result.

                                                                  To simplify things from the input/output dependency perspective, we have set up different "levels" of analysis template. So, if a recalculation is needed, we will first remove values from the affected tags, then we will manually kick off the recalc of analyses at "level 1" template, followed by "level 2" template, "level 3"  template and so forth (so that the inputs for the template next level up will be ready before we kick off the calculation at that level).

                                                                  Now, the problem that we encountered when doing this is that the recalculation doesn't seem to be reliable. Quite often, recalculating all analyses for a particular analysis template will not end up to be correctly populating all the outputs of these analyses. But we were not aware of that and will proceed to run "level 2" template and so on because we assume that the calculation has been successful since it has run to completion. After the whole things have completed, the users may then go and check some of the results and find that the result doesn't look right. At that point, we will then have to repeat the whole process once more, i.e. clearing the data, rerun the different levels of calculation, and hope that the data will be right this time!

                                                                  The problem with the aforementioned approach is we do not know which calculation has actually failed. Hence, if the result is wrong, we will have to redo the whole things for every analysis. Having hundreds of elements that require recalculation also means that we do not want to go through each analysis on each element one at a time to verify the calculation is successful.

                                                                  It is for the above reason that we have tried to build our recalc engine using AF SDK that we can easily control the order of execution and troubleshoot ones that have failed.

                                                                  However, whereas the recalc triggered by the built-in PI Analytic Engine is quick (though its reliability is arguable especially for large number of analyses in a given template), the code given above using a for loop to get evaluation result one timestamp at a time is proving to be quite slow when evaluating say 100 days of analysis at 15-minute interval for 100 analyses. For example, it takes about 30 seconds to process one of our 15-minute interval analyses over a day using a for loop. That means it will take roughly 100(d) x 100(analyses) x 30 sec = 3.4 days to complete this calculation by code. So, I suspect there must be something different that the built-in engine is using which allows it to complete such calculation faster as it certainly wouldn't take that long to run (perhaps due to it being multi-threaded?). The bottleneck as I can see is the for loop. Just like in PI SDK where you can use a loop to get PI value one at a time until you get all values over the entire period of interest or you can get all the values in one hit for that period with exactly the same result but in much shorter time, I am hoping that there is similar function in AF SDK when it comes to evaluating analyses result.

                                                                  I hope this clarifies the intention of my original question. Please let me know if you have a better solution to address this issue.

                                                                  Thank you.

                                                                   

                                                                  Regards,

                                                                  Chia

                                                                    • Re: Get Results from Analysis without defining an Output Attribute
                                                                      Mike Zboray

                                                                      I understand. The example was not intended as an industrial grade implementation of recalculation. It was intended as a sample for implementing a simple preview-like feature. There are additional considerations when building a recalculation engine. For example, data access by AFAnalysisRuleState is somewhat naive. The Analysis Engine has its own implementation of IAFAnalysisRuleState for online and recalculation/backfill scenarios to cache as much data as possible without keeping unnecessary data. This implementation is non-trivial and not exposed publicly. Second, writing data is not shown at all here but bulk writes are required for maximum throughput. Finally, at the core of the recalculation engine in the Analysis Service is a loop very similar to one you see above. It is in fact not multi-threaded, at least not at the level of evaluating analyses. The data access is done efficiently in a custom implementation of IAFAnalysisRuleState. Unfortunately there is not good documentation on how one would go about implementing this.

                                                                       

                                                                      As for your results not being correct when using the Analysis Service, I would urge you to contact tech support and file a bug if you have not done so already.

                                                                      1 of 1 people found this helpful