16 Replies Latest reply on Nov 16, 2017 7:14 PM by Rick Davin

    IPICalculation.Calculate equivalent in AFSDK example ?

    Chirag89

      Hi,

       

      I am trying to upgrade from PISDK to AFSDK. At some places i can see to calculate the initial, final, avg, min, max values related to a point for a specific time range, IPICalculation.Calculate method is used :

      eg:     

      PISDK.IPICalculation objPICalculation;

      var objPIAverageValues = objPICalculation.Calculate(startTime, endTime, "tagavg('" + piTag.TagName + "','*+" + intMinutes.ToString() + "m','*')", PISDK.SampleTypeConstants.stRecordedValues, null, null);

       

      objPIInitialValue = objPICalculation.Calculate(startTime, startTime, "tagval('" + piTag.TagName + "','*')", PISDK.SampleTypeConstants.stRecordedValues, null, null);

       

      objPIFinalValue = objPICalculation.Calculate(endTime, endTime, "tagval('" + piTag.TagName + "','*')", PISDK.SampleTypeConstants.stRecordedValues, null, null);

       

      objPIMaxValue=objPICalculation.Calculate(startTime,endTime,"tagmax('"+piTag.TagName+"','*-"+intMinutes.ToString()+"m','*')",PISDK.SampleTypeConstants.stRecordedValues,null,null);

       

      Now this operation is done on individual point. For multiple tags, this operation is done inside a loop. While using AFSDK, i want to use same kind of method on PIPointList instead of individual point for better performance/bulk data retrieval.

       

      Can somebody help me in achieving the same with some syntax ?

        • Re: IPICalculation.Calculate equivalent in AFSDK example ?
          Rick Davin

          Hi Chirag,

           

          One of the first pages you seen with AF SDK's Live Library Help is

           

          PI SDK Equivalents

           

          The 5th one down states that IPICalculation has an AF SDK equivalent of AFCalculation, which has examples that should get you started.  However, that just like IPICalculation, AFCalculation produces results for ONE calculation.  If you have performance issues, and desire some bulk processing to as a performance boost, then you may consider fetching all the data and performing the calculation yourself.

          3 of 3 people found this helpful
            • Re: IPICalculation.Calculate equivalent in AFSDK example ?
              Chirag89

              I thought of calculating the min, max, average through custom code, but how about the time interval provided,

              eg :  tagmax('"+piTag.TagName+"','*-"+intMinutes.ToString()+"m','*'),

              How can i achieve it in my code ?

               

              Can i achieve the same using some other method which accepts time interval as well?

                • Re: IPICalculation.Calculate equivalent in AFSDK example ?
                  Chirag89

                  Can i use PIPointList.Summary method, to achieve the same result, if there is any way to pass the interval as well ?

                  • Re: IPICalculation.Calculate equivalent in AFSDK example ?
                    Rick Davin

                    Hi Chirag,

                     

                    I would strongly discourage you from attempting to write custom summary methods for PI Points.  There are two PIPointList.Summaries overloads available to you.  One of them should do the trick.

                      • Re: IPICalculation.Calculate equivalent in AFSDK example ?
                        Chirag89

                        Hi Rick,

                         

                        Thanks for your reply, i've tried using PIPointList.Summaries, but there is data difference while using IPICalculation.Calculate/AFCalculation.Calculate and PIPointList.Summaries, here is my piece of code :

                         

                        var startAFt = new AFTime("3/21/2017 3:37:00 PM");

                        var endAFt = new AFTime("3/21/2017 5:37:00 PM");

                        var aftrange = new AFTimeRange(startAFt, endAFt);

                         

                        var tags = new PIPointList(PIPoint.FindPIPoints(server, _plantName + ".*", null, attributeNames: requestedAttributes));

                         

                        IEnumerable<IDictionary<AFSummaryTypes, AFValues>> avgSummaryData = tags.Summaries(aftrange, new AFTimeSpan(minutes: 120), AFSummaryTypes.Average, AFCalculationBasis.TimeWeighted, AFTimestampCalculation.Auto, configObj);

                         

                        Using IPICalculation.Calculate()

                         

                        PISDK.PISDK objPISDK = new PISDK.PISDK();

                        var objPISDk = (PISDK.IPICalculation)objPISDK.Servers["servername"];

                         

                        tags.ToList().ForEach((tag) =>

                        {

                             var res = objPISDk.Calculate(startAFt.ToString(), endAFt.ToString(), "tagavg('" + tag.Name + "','*-120m','*')",      PISDK.SampleTypeConstants.stRecordedValues, null, null);

                             Console.WriteLine(tag.Name + " : " + GetValue(res));

                        });

                        GetValue()

                        {

                        ...

                        }

                         

                        Can you see anything wrong here ?, and i am looking for a solution which can return me the same values,

                        NOTE : I don't want to makes calls to server inside a loop using Calculate(), so i am looking for a better approach.

                         

                        Thanks.

                          • Re: IPICalculation.Calculate equivalent in AFSDK example ?
                            Rick Davin

                            I see no reason to mix AF SDK and PI SDK.  Replace the PI SDK code with AF SDK, in other words, use AFCalculation instead of IPICalculation.  Note neither AFCalculation nor IPICalculation use bulk calls.  But you don't need to use either of the calculation calls.  Your custom calculation isn't that custom.  Rather you are using a standard TagAvg call but with unneeded and awkward overhead of wrapping it inside a custom calculation.

                             

                            What exactly are you trying to average? For a given time range, there are generally 2 ways to summarize over that time range.  One way is aggregating over the entire time range to produce a single average per tag.  The other way is to aggregate over intervals within the time range to produce many averages (one per interval) per tag.  For the AF SDK call, you are calling this PIPointList.Summaries overload but your passed intervals is the entire time range.  If that's what you want, the simpler and more direct way would be to call PIPointList.Summary.

                    • Re: IPICalculation.Calculate equivalent in AFSDK example ?
                      gachen

                      Hi Chirag,

                       

                      Just based on your initial entry, I have several suggestions:

                      • Looking at the original PISDK code, I would say that it is not well-optimized for the problem. First of all, it is best to avoid expressions altogether, whenever possible. Expression-based queries tend to be less-efficient, and are more prone to cause issues on the server. Additionally, in this case it seems we are trying to get summary calculation values, and there are specific functions in both PISDK and AFSDK to make summary calls to the server. Using these functions are generally the most efficient ways to get summary data, since the server also has reciprocal functions specifically designed for such purposes.
                        • For example, instead of:
                          objPICalculation.Calculate(startTime, endTime, "tagavg('" + piTag.TagName + "','*+" + intMinutes.ToString() + "m','*')", PISDK.SampleTypeConstants.stRecordedValues, null, null)
                          consider something like (exact syntax may be slightly different):
                          PIData.Summaries(startTime, endTime, asAverage, cbTimeWeighted)
                        • The idea is to use purpose-built functions to perform the summary, rather than by doing it via IPICalculation.Calculate and expressions. In a similar way to the example above, you should be able to get the Min and Max values over a time range as well.
                        • For getting the values at the start and end of the time range, there is no reason at all to use expressions. Simply:
                          PIData.ArcValue(startTime /*or endTime*/, rtAuto)
                        • Of course, the examples I provided above are still in PISDK, but you get the idea. Rick provided a good link in translating these data calls to the appropriate AFSDK calls.
                      • I am very pleased that you are taking performance considerations seriously in your refactor. As with any summary type calculation, caution must be used to make sure the summary time ranges are reasonable and appropriate, to prevent performance issues on the server, which may even affect other users. I have personally seen countless cases in support stemming from poor performance because of out-of-control summary calculations.
                        • As referenced in the thread, AFSDK allows you take advantage of using PIPointList.Summaries. This does have the advantage of using bulk calls, if your server supports it (version 390+). Overall computation time on the server likely will not decrease by much, but this would reduce some traffic over the network and allow results to return asynchronously as they are ready.
                        • Another suggestion I have regarding performance is that if you are expecting to calculate multiple summary values for the points (e.g. Average, Min, Max), make use of the AFSummaryTypes.All enumeration option. You might think that this incurs extra cost on the server by calculating all summary values, but in fact this is more efficient than making separate calls each for Average, Min and Max, for example. The reason is simple: regardless of what summary type the server is told to calculate, it always calculates all of them anyway. So might as well take advantage of this and just call for all of them once, and iterate through them client-side.
                      • General suggestion about how the PISDK code was written, specifically regarding this: "tagavg('" + piTag.TagName + "','*+" + intMinutes.ToString() + "m','*')"
                        • If you are not careful with the validation on piTag.TagName, this kind of string concatenation is prone to injection-type attacks/vulnerabilities. Users can take advantage of this by putting their own arbitrary expression into piTag.TagName to make your program do something unexpected.

                       

                       

                      I know I didn't provide much in translating specific syntax into AFSDK, but Rick's link and suggestions should be a good start. It seems to me that you would want to take advantage of PIPointList.Summaries with the AFSummaryTypes.All option. Let us know if you have any questions. Hope that helps!

                       

                      1 of 1 people found this helpful
                        • Re: IPICalculation.Calculate equivalent in AFSDK example ?
                          Chirag89

                          Thanks Gavin for your concern, well i have tried IPICalculation.Calculate method from (PISDK existing solution) for individual calls and PIPointList.Summary/Summaries method (AFSDK new piece of code) for bulk calls, but the result data is not matching for the above syntax.

                          I am trying to upgrade my code from PISDK to AFSDK, the data result from my new code must match with data result of existing code.

                          I am trying to upgrade this from :

                          inside loop() {

                          var values = objPICalculation.Calculate(startTime, endTime, "tagavg('" + piTag.TagName + "','*+120m','*')", PISDK.SampleTypeConstants.stRecordedValues, null,

                          null)

                          }

                           

                          to :

                          AFTimeSpan tspn = new AFTimeSpan(minutes: 120);

                          IEnumerable<IDictionary<AFSummaryTypes, AFValues>> summaryDatas = tags.Summaries(aftrange, tspn,

                               AFSummaryTypes.Average, AFCalculationBasis.TimeWeighted, AFTimestampCalculation.Auto, config);

                           

                          I was expecting the same result from both of the queries, but i can see that the data is not matching, to be very exact the result derived from Summaries method is actually shifted one interval forward as compared to the result derived from IPICalculation.Calculate method

                           

                          Results derived from IPICalculation.Calculate() :

                              

                          Log Reading LabelUOM3/21/2017 15:373/21/2017 17:373/21/2017 19:373/21/2017 21:373/21/2017 23:37

                          3/22/2017

                          1:37

                          Barometric PressureMM HG750.2188144750.6408875751.5665492752.8130403754.3076219755.5900136
                          L/O Feed RateGRAMS/HR65.46487666228.518934229.4672776227.3271958195.7589925150.792953
                          L/O Feed Rate 388GRAMS/HR88.6989981688.6966695888.7061300288.691161588.6835865588.6932395

                           

                          -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

                          Results derived from PIPointList.Summaries() :

                              

                          Log Reading LabelUOM3/21/2017 15:373/21/2017 17:373/21/2017 19:373/21/2017 21:373/21/2017 23:37

                          3/22/2017

                          1:37

                          Barometric PressureMM HG750.6408875751.5665492752.8130403754.3076219755.5900136756.4296859
                          L/O Feed RateGRAMS/HR228.518934229.4672776227.3271958195.7589925150.792953227.4048792
                          L/O Feed Rate 388GRAMS/HR88.6966695888.7061300288.691161588.6835865588.693239588.69070985

                           

                          Here, you can see that the data is shifted one interval forward. I am not able to figure out what's wrong in here ?

                            • Re: IPICalculation.Calculate equivalent in AFSDK example ?
                              Rick Davin

                              Hi Chirag,

                               

                              So you have 2 differing result sets.  What makes you think the one using Calculate is the golden set?  Can you acknowledge the possibility exists that the Calculate set may be the one with the wrong results?

                                • Re: IPICalculation.Calculate equivalent in AFSDK example ?
                                  Chirag89

                                  Hi Rick,

                                   

                                  Data set result using Calculate was implemented using PISDK in my solution in 2007-08, now the application is already consuming the returned data using Calculate method, which i am trying to upgrade. I am not sure whether the earlier implementation was intentionally done using expression query or it is wrong, because this application is already running and in use, that's what making it final result for me to match. I doubt, there is some issue while passing interval to AFSDK Summaries method. Can you confirm how can we achieve the same result using Summaries(), I've already provided the query syntax used with PISDK Calculate() in previous conversation.

                                   

                                  Thanks.

                                    • Re: IPICalculation.Calculate equivalent in AFSDK example ?
                                      Rick Davin

                                      On Nov 8, you used this line of code:

                                       

                                      var res = objPISDk.Calculate(startAFt.ToString(), endAFt.ToString(), "tagavg('" + tag.Name + "','*-120m','*')",      PISDK.SampleTypeConstants.stRecordedValues, null, null);

                                       

                                      and today (Nov 10), you used this line.

                                       

                                      var values = objPICalculation.Calculate(startTime, endTime, "tagavg('" + piTag.TagName + "','*+120m','*')", PISDK.SampleTypeConstants.stRecordedValues, null, null)

                                       

                                      Can you confirm which relative start time is correct?

                                        • Re: IPICalculation.Calculate equivalent in AFSDK example ?
                                          Chirag89

                                          Rick,

                                           

                                          This one is correct :

                                          var res = objPISDk.Calculate(startAFt.ToString(), endAFt.ToString(), "tagavg('" + tag.Name + "','*-120m','*')",      PISDK.SampleTypeConstants.stRecordedValues, null, null);

                                           

                                          I tried AFTimestampCalculation.MostRecentTime as well, but getting the same results.

                                          Thanks for showing your great concern, i'll try to dig more by talking to the team who implemented it initially and will get back to you.

                                            • Re: IPICalculation.Calculate equivalent in AFSDK example ?
                                              Rick Davin

                                              Hello Chirag,

                                               

                                              I just want to confirm that PIPointList.Summaries is producing the correct numerical averages, but that your concern is over the associated Timestamp for a given average.

                                                  • Re: IPICalculation.Calculate equivalent in AFSDK example ?
                                                    Rick Davin

                                                    Hello Chirag,

                                                     

                                                    So you have 2 objectives: (1) you would like to switch from PI SDK over to AF SDK, and (2) you would like to make a bulk call, if possible.  Neither IPICalculation nor AFCalculation works in bulk, but PIPointList.Summaries does.  This bulk Summaries call gives you the correct numeric average for a requested time range, but you don't like the timestamp associated with each value.

                                                     

                                                    I get it.  I was in your same shoes 7 years ago.  I was performing daily calculations in ACE at the time.  And I was very rigid in that the calculations for a given Monday could not be performed until Tuesday at midnight (that would be the Monday-Tuesday midnight, not the Tuesday-Wednesday one).  And in my strict thinking the timestamp was Tuesday midnight because the calculation covered the range of Monday midnight through Tuesday midnight.  Actually to split hairs and be more precise, the end of the time range was Monday 11:59:59 PM.

                                                     

                                                    When I would display those values in a spreadsheet, I was gracious not to overload the reader with a heading of "11/13/2017 00:00:00 AM - 11/13/2017 11:59:59 PM".  Plus that would make for one quite unnecessarily wide column.  Instead, I simplified the column heading to be "11/13/2017", which was also wide enough to display the calculated value.  All was well and I congratulated myself on being both precise with a timestamp of "11/13/2017 11:59:59 PM" but also concise in reports with a simple heading of "11/13/2017".  The heading represented the time range, and not a specific point in time, namely midnight.

                                                     

                                                    And then someone wanted to trend the averages.  The problem was the calculation was applicable to entirety of a given day, but since the timestamp was at the end of the day, what appeared to be Monday's data was actually Sunday's, and Monday's data showed up under Tuesday.  It was very confusing to others.  After much deliberation, I changed my thinking and accepted it as quite appropriate that a given calculation (and an Average is such a calculation) for a time range should probably have its timestamp as the beginning of the time range because it will trend correctly.

                                                     

                                                    So you have a choice before you.  If you would be open to the timestamp being the beginning of a time range, you may switch to AF SDK and use bulk calls.

                                                    1 of 1 people found this helpful
                                        • Re: IPICalculation.Calculate equivalent in AFSDK example ?
                                          Rick Davin

                                          Regarding timestamps seemingly shifted one interval for the AF SDK PIPointList.Summaries call, try using AFTimestampCalculation.MostRecentTime.