4 Replies Latest reply on Oct 10, 2016 7:10 PM by Rick Davin

    Trying to iterate over attributes and check for bad point references.

    BrianFONeil

      I am trying to loop over the attributes in a PI AF database, and set them to Excluded if they do not point to a valid PI Point.

       

      I have this block of code, which makes the decision for an attribute, and wonder if there would be a more performant way to do it?

       

      try
      {
          AttributeCount++;
          string Point = subElement.Attributes[i].DataReference.PIPoint.Name;
          if (subElement.Attributes[i].IsExcluded)
          {
              subElement.Attributes[i].IsExcluded = false;
          }
      }
      catch (System.Exception exception)
      {
          BadAttributes++;
          subElement.Attributes[i].IsExcluded = true;
      }
      

       

      As may be consensus, running a Try Catch over every attribute may be causing slow performance of this code.

       

      Thanks

       

      Message was edited by: Rick Davin.  Added C# syntax highlighting.

        • Re: Trying to iterate over attributes and check for bad point references.
          Rick Davin

          Hi Brian,

           

          Slow performance is most likely due to issuing a call for each individual attribute.  I would encourage you to issue a bulk call instead.

           

          AFAttributeList.GetPIPoint Method

           

          Note that an AFAttributeList is required for the bulk call.  This is quite easy to do:

           

          AFAttributeList attrList = new AFAttributeList(subElement.Attributes);
          AFKeyedResults<AFAttribute, PIPoint> pointMap = attrList.GetPIPoint();
          

           

          The AttributeCount is obtained via attrList.Count.  The good versus bad count is:

           

          int goodCount = pointMap.Results.Count;
          int badCount = attrList.Count - goodCount;
          

           

          That should point you in the right direction.

          Rick

            • Re: Trying to iterate over attributes and check for bad point references.
              BrianFONeil

              Thanks for the suggestion.

               

              First thing I notice is the PointMap just does not populate with an item for anything with missing PI Point.

              Then it does populate an "Errors" collection with Key/Value for things that do not have a good Point reference.

              But when I try to pick this apart in the debugger (pointMap.Errors[0].Key)    , I get this exception.

               

               

                     pointMap.Errors[0] error CS1503: Argument 1: cannot convert from 'int' to 'OSIsoft.AF.Asset.AFAttribute'

               

              So this change is non-trivial to say the least. I can keep trying  to make it work, if it promises a big performance improvement.

               

              Thanks

                • Re: Trying to iterate over attributes and check for bad point references.
                  BrianFONeil

                  Just an update. The properties of the Errors collection items are working well in runtime. This is just one of those things that does not evaluate well in the Watch window.

                   

                  I think this approach is an improvement on my performance, although presents some extra logic to be put in place if I want to reverse the Excluded property.

                   

                  Thanks for the help.

                    • Re: Trying to iterate over attributes and check for bad point references.
                      Rick Davin

                      Good to hear, Brian.  To touch upon a few other things:

                       

                      Perhaps your example was intentionally simplified with subElement[0].Attributes, which only grabs the attributes from the element's root.  If you wanted all generations of attributes, that is children, grand-children, etc., I have a few C# 6.0 methods that help do that.  See my answer on this post for the GetFlatAttributeList method, which relies upon my GetAllAttributeGenerations recursive method.

                       

                      It's rare to think every attribute on an element is a PIPoint, so you can filter out the possible PIPoints first with this quick and super fast method:

                       

                      public static bool UsesPIPointDR(this AFAttribute attribute) => attribute.DataReferencePlugIn != null && attribute.DataReferencePlugIn.ID == AFDataReference.GetPIPointDataReference().ID;
                      

                       

                      That would filter your attribute list to be only those that have the PIPoint data reference.  Just because it uses the PIPoint data reference doesn't mean the attribute is configured correctly or references a valid PIPoint.  And that bring us to your original question.

                       

                      AFAttributeList fullAttributeList = subElement.GetFlatAttributeList();
                      AFAttributeList attrList = new AFAttributeList(fullAttributeList.Where(x => x.UsesPIPointDR() == true));
                      AFKeyedResults<AFAttribute, PIPoint> pointMap = attrList.GetPIPoint();
                      
                      int goodCount = 0;
                      int badCount = 0;
                      foreach (var item in pointMap.Results)
                      {
                           // Set Attribute's IsExcluded based on whether PIPoint is valid
                             item.Key.IsExcluded = item.Value == null;
                          if (item.Value != null)
                          {
                              goodCount++;
                              // item.Key is the AFAttribute with the good PIPoint
                          }
                          else
                          {
                              badCount--;
                              // item.Key is the AFAttribute with the bad PIPoint
                          }
                      }
                      
                      1 of 1 people found this helpful