9 Replies Latest reply on Aug 10, 2018 6:08 AM by Roger Palmen Branched from an earlier discussion.

    "No Data" on future PI Point disappears after writing the next "No Data" event

    Hans_Drost

      It has been some time ago since I implemented this.
      Now I see a weird reaction to the "No-Data" writing into a future data tag. The following is the situation in which I write "No-Data":

      For a customer we write a perfect batch trend into the future.

      To make sure we see exactly when a batch should start/stops, we write a "No-Data" at the end of each perfect batch planning.

      In other words, when a batch starts, we write an x amount of data into the future ending with a "no-data" value.

       

      Now, the No-Data stay's fine, until the next batch starts and a new perfect batch planning is written into the future.

      When this happens, we get an interpolated value instead of a broken up line in a trend.

      Also, the No-Data has disappeared in the archive!

       

      Anyone know how this is possible? Is a no-data in the future replaced with the next data written to it after the no-data timestamp?

        • Re: "No Data" on future PI Point disappears after writing the next "No Data" event
          gregor

          Hello Hans,

           

          Continuing a question which already has a [Correct Answer] is not ideal and hence I've branched your latest post to this other question into a new question.

          I hope that I understood your problem properly and the title of this new question is sufficient.

           

          PI Event Frames is what we (OSIsoft) suggest for batch processes. One of the advantages is that Event Frames always have a defined start and, when completed, a defined end. Actual process data can be compared to ideal process data as identified by a Golden Batch. Have you looked into using Event Frames for your purposes? Is the Golden Batch depending on actual conditions which make you want to predict the Golden Batch for each batch process?

           

          I wouldn't know there is a special handling of SYSTEM Digital States with future data PI Points which would explain your observations. Can you share some code allowing to reproduce your experience?

          • Re: "No Data" on future PI Point disappears after writing the next "No Data" event
            Roger Palmen

            For all reading this thread some background info. Yes, we do use EventFrames to solve parts of the functionality, but in this case we are looking at strange behaviour when we determine a 'forecast' for the batch variables.

            In essence, when a bacth starts we determine the forecast and write that to a future data point. At the end of that forecast we write a No Data event. When the next batch starts, we start with a No Data event, and then write the new forecast for the new batch. This should create a 'gap' framed by 2 NoData events between subsequent batches.

             

            The issue we are investigating is that we do write the NoData values, but they disappear from the set of Archived values. We'll come back to this when we have isolated the issue a bit more.

              • Re: "No Data" on future PI Point disappears after writing the next "No Data" event
                gregor

                Hi Roger,

                 

                Glad to read you are using Event Frames for Batch processes.

                Regarding your experience with Future Data PI Points, do you like to share the code used to write those updates. This would enable us to a) review the code and potentially identify any flaws with it and b) to confirm a potential bug with the PI Data Archive or an AF SDK method.

                  • Re: "No Data" on future PI Point disappears after writing the next "No Data" event
                    Roger Palmen

                    The code is spread around a larger solution, but some code snippets:

                     

                    Adding NoData values to the set of values to write:

                                limits.Add(AFValue.CreateSystemNoDataFound(attLimit_L, tsBE));
                                limits.Add(AFValue.CreateSystemNoDataFound(attLimit_Target, tsBE));
                                limits.Add(AFValue.CreateSystemNoDataFound(attLimit_H, tsBE));
                    

                    Actually writing:

                        AFErrors<AFValue> errors = AFListData.UpdateValues(limits, AFUpdateOption.Insert);
                    

                     

                    My first presumption there is nothing technically wrong with the code, but we actually delete the data by coincidence, or replace the values. But i'll need to prove that first.

                      • Re: "No Data" on future PI Point disappears after writing the next "No Data" event
                        gregor

                        Hi Roger,

                         

                        I have tested with the behavior and was not able to reproduce your observation.

                         

                        The code of the console application I've used is the following one:

                         

                        using OSIsoft.AF;
                        using OSIsoft.AF.Asset;
                        using OSIsoft.AF.Data;
                        using OSIsoft.AF.Time;
                        using System;
                        using System.Collections.Generic;
                        using System.Threading;
                        
                        
                        namespace p37424a
                        {
                            class Program
                            {
                                static PISystem sys;
                                static string hostName = "GB-PISystem";
                                static AFDatabase afDB;
                                static string afDBName = "Sandbox";
                                static AFElement afEL;
                                static string rootElName = "p37424";
                                static Random rnd;
                                static List<AFAttribute> attrL;
                                static int eventsPerWrite = 10;
                                static void Main(string[] args)
                                {
                                    InitApp();
                                    Console.WriteLine("Will write against {0} Attributes ... ", attrL.Count);
                                    Console.WriteLine("Press [Esc] to quit.");
                                    Boolean bActive = true;
                                    while (bActive)
                                    {
                                        int iSecond = DateTime.Now.Second;
                                        Console.SetCursorPosition(0, Console.CursorTop);
                                        Console.Write("Countdown: {0:00}", 60 - iSecond);
                                        if (iSecond == 0)
                                        {
                                            WriteValues();
                                        }
                                        while (Console.KeyAvailable)
                                        {
                                            ConsoleKey cKey = Console.ReadKey().Key;
                                            if (cKey == ConsoleKey.Escape) { bActive = false; }
                                        }
                                        Thread.Sleep(1000);
                                    }
                        
                        
                                    Console.WriteLine();
                                    Console.Write("Done. Press any key to quit .. ");
                                    sys.Disconnect();
                                    Console.ReadKey();
                                }
                        
                        
                                static void InitApp()
                                {
                                    InitAttributeList();
                                    InitRandom();
                                }
                        
                        
                                static void InitAttributeList()
                                {
                                    if (sys == null) { sys = new PISystems()[hostName]; }
                                    afDB = sys.Databases[afDBName];
                                    afEL = afDB.Elements[rootElName];
                                    attrL = new List<AFAttribute>();
                                    attrL.AddRange(afEL.Attributes);
                                }
                                static void InitRandom()
                                {
                                    if (rnd == null) { rnd = new Random(DateTime.Now.Second); }
                                }
                        
                        
                                static double NextRandomDouble()
                                {
                                    return (rnd.NextDouble() * 100);
                                }
                        
                        
                                static void WriteValues()
                                {
                                    AFValues values = new AFValues();
                                    for (int i = 0; i < 11; i++)
                                    {
                                        AFTime valueTime = AFTime.NowInWholeSeconds.LocalTime.AddHours(3).AddSeconds(i);
                                        foreach (AFAttribute attr in attrL)
                                        {
                                            AFValue val = new AFValue(NextRandomDouble(), valueTime);
                                            if (i == eventsPerWrite)
                                            {
                                                val = AFValue.CreateSystemNoDataFound(attr, valueTime);
                                            }
                                            val.Attribute = attr;
                                            values.Add(val);
                                        }
                                    }
                                    Console.SetCursorPosition(0, Console.CursorTop);
                                    Console.WriteLine("Writing {0} events .. ", values.Count);
                                    AFErrors<AFValue> errors = AFListData.UpdateValues(values, AFUpdateOption.Insert);
                                    if (errors != null && errors.HasErrors)
                                    {
                                        foreach (KeyValuePair<AFValue, Exception> err in errors.Errors)
                                        {
                                            Console.WriteLine("{0} : {1}", err.Key, err.Value);
                                        }
                                    }
                                }
                            }
                        }