Ejemplo n.º 1
0
        /// <summary>
        ///  If it is a new search, the elements that fit the criteria are collected and the first is selected.
        ///  Else it iterates through the collection of elements and expands to the node.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bSearchElements_Click(object sender, EventArgs e)
        {
            currentTreeSearchTimes++;
            if (currentTreeSearch == tbElementSearchName.Text)
            {
                if (currentSearchResults.Count == 0)     //No search results
                {
                    Status("Couldn't find Element Name");
                    return;
                }
                else if (currentTreeSearchTimes < currentSearchResults.Count)     // iterate through.
                {
                    findTreeNode(afTreeViewElements.Nodes[0], currentSearchResults[currentTreeSearchTimes]);
                }
                else     //restart iteration through.
                {
                    currentTreeSearchTimes = 0;
                    findTreeNode(afTreeViewElements.Nodes[0], currentSearchResults[currentTreeSearchTimes]);
                }
            }
            else     //Load Search Results
            {
                currentTreeSearchTimes = 0;
                currentTreeSearch      = tbElementSearchName.Text;
                AFDatabase afdb = control.getAFDatabase();
                currentSearchResults = AFElement.FindElements(afdb, null, "*" + tbElementSearchName.Text + "*", AFSearchField.Name, true, AFSortField.Name, AFSortOrder.Ascending, Int32.MaxValue);

                if (currentSearchResults.Count > 0)
                {
                    findTreeNode(afTreeViewElements.Nodes[0], currentSearchResults[currentTreeSearchTimes]);
                }
            }
        }
Ejemplo n.º 2
0
        public void Run()
        {
            PISystems piSystems = new PISystems();
            PISystem  piSystem  = piSystems["<AFSERVER>"];

            AFDatabase afDatabase = piSystem.Databases["NuGreen"];

            const int pageSize   = 1000;
            int       startIndex = 0;
            int       totalCount;

            do
            {
                // Find a collection of elements instantiated from the Boiler tempplate.
                // Only the Elements' header information (Name, Description, Template, Type, etc.)
                // are loaded from the AF Server by this call.
                AFNamedCollection <AFElement> elements = AFElement.FindElements(
                    database: afDatabase,
                    searchRoot: null,
                    query: "Boiler",
                    field: AFSearchField.Template,
                    searchFullHierarchy: true,
                    sortField: AFSortField.Name,
                    sortOrder: AFSortOrder.Ascending,
                    startIndex: startIndex,
                    maxCount: pageSize,
                    totalCount: out totalCount);
                if (elements == null)
                {
                    break;
                }

                // This call goes to the AF Server to fully load the found elements in one call,
                // so further AF Server calls can be avoided.
                AFElement.LoadElements(elements);

                // Now we can use the elements without having to make any additional server calls.
                // In the example below, accessing the Attributes collection would have
                // caused an additional call per element if we had not called LoadElements previously.
                Console.WriteLine("Found {0} Elements.", elements.Count);
                foreach (AFElement item in elements)
                {
                    Console.WriteLine("  Element {0} has {1} Attributes", item.Name, item.Attributes.Count);
                }

                startIndex += pageSize;
            } while (startIndex < totalCount);
        }
Ejemplo n.º 3
0
        public void Run()
        {
            PISystems piSystems = new PISystems();
            PISystem  piSystem  = piSystems["<AFSERVER>"];

            AFDatabase afDatabase = piSystem.Databases["NuGreen"];

            const int pageSize   = 1000;
            int       startIndex = 0;
            int       totalCount;

            do
            {
                // Find a collection of elements instantiated from the Boiler tempplate.
                // Only the Elements' header information (Name, Description, Template, Type, etc.)
                // are loaded from the AF Server by this call.
                AFNamedCollection <AFElement> elements = AFElement.FindElements(
                    database: afDatabase,
                    searchRoot: null,
                    query: "Boiler",
                    field: AFSearchField.Template,
                    searchFullHierarchy: true,
                    sortField: AFSortField.Name,
                    sortOrder: AFSortOrder.Ascending,
                    startIndex: startIndex,
                    maxCount: pageSize,
                    totalCount: out totalCount);
                if (elements == null)
                {
                    break;
                }

                // Because we are just retrieving the element's name, no additional calls
                // to the AF Server are made.
                Console.WriteLine("Found {0} Elements.", elements.Count);
                foreach (AFElement item in elements)
                {
                    Console.WriteLine("  Element name is {0}.", item.Name);
                }

                startIndex += pageSize;
            } while (startIndex < totalCount);
        }
        private List <string> FindChildElementTemplates()
        {
            List <string> _templateNames = new List <string>();

            try
            {
                if (dataReference.Attribute != null)
                {
                    AFElement element = (AFElement)dataReference.Attribute.Element;
                    AFNamedCollectionList <AFElement> childElements = AFElement.FindElements(element.Database, element, "*",
                                                                                             AFSearchField.Name, false, AFSortField.Name, AFSortOrder.Ascending, 1000000);

                    if (childElements != null && childElements.Count > 0)
                    {
                        foreach (AFElement childElement in childElements)
                        {
                            if (!(_templateNames.Contains(childElement.Template.Name)))
                            {
                                _templateNames.Add(childElement.Template.Name);
                            }
                        }
                    }
                }

                if (dataReference.Template != null)
                {
                    foreach (AFElementTemplate template in dataReference.Database.ElementTemplates)
                    {
                        _templateNames.Add(template.Name);
                    }
                }

                _templateNames.Sort();
                return(_templateNames);
            }
            catch
            {
                return(null);
            }
        }
        public void Run()
        {
            PISystems piSystems = new PISystems();
            PISystem  piSystem  = piSystems["<AFSERVER>"];

            AFDatabase afDatabase = piSystem.Databases["NuGreen"];

            AFElementTemplate boilerTemplate = afDatabase.ElementTemplates["Boiler"];

            const int pageSize   = 1000;
            int       startIndex = 0;
            int       totalCount;

            do
            {
                // Find a collection of elements instantiated from the Boiler tempplate.
                // Only the Elements' header information (Name, Description, Template, Type, etc.)
                // are loaded from the AF Server by this call.
                AFNamedCollection <AFElement> elements = AFElement.FindElements(
                    database: afDatabase,
                    searchRoot: null,
                    query: "Boiler",
                    field: AFSearchField.Template,
                    searchFullHierarchy: true,
                    sortField: AFSortField.Name,
                    sortOrder: AFSortOrder.Ascending,
                    startIndex: startIndex,
                    maxCount: pageSize,
                    totalCount: out totalCount);
                if (elements == null)
                {
                    break;
                }

                // Partially load the element by retrieving information only for the Water Flow attribute.
                AFElement.LoadAttributes(elements, new[] { boilerTemplate.AttributeTemplates["Water Flow"] });

                Console.WriteLine("Found {0} Elements.", elements.Count);

                AFAttributeList attrList = new AFAttributeList();

                // Because we are retrieving the Water Flow attribute which was previously loaded,
                // no additional server calls are made.
                // If LoadAttributes had not been called previously, then a server call would have been made for each element
                // in the loop below.
                foreach (AFElement item in elements)
                {
                    attrList.Add(item.Attributes["Water Flow"]);
                }

                AFValues values = attrList.GetValue();

                Console.WriteLine("  Water Flow values");
                foreach (AFValue val in values)
                {
                    Console.WriteLine("  Element: {0}, Timestamp: {1}, Value: {2}",
                                      val.Attribute.Element, val.Timestamp, val.Value.ToString());
                }

                startIndex += pageSize;
            } while (startIndex < totalCount);
        }
Ejemplo n.º 6
0
        static void Main(string[] args)
        {
            //define variables
            string user_path           = null;
            string user_serv           = null;
            string user_db             = null;
            string user_analysisfilter = null;
            string user_mode           = null;

            PIServer                 aPIServer        = null;
            PISystems                aSystems         = new PISystems();
            PISystem                 aSystem          = null;
            AFAnalysisService        aAnalysisService = null;
            AFDatabase               aDatabase        = null;
            List <AFElement>         foundElements    = new List <AFElement>();
            List <AFAnalysis>        foundAnalyses    = new List <AFAnalysis>();
            IEnumerable <AFAnalysis> elemAnalyses     = null;

            AFTimeRange backfillPeriod = new AFTimeRange();

            AFAnalysisService.CalculationMode mode = AFAnalysisService.CalculationMode.FillDataGaps;
            String reason   = null;
            Object response = null;

            String help_message = "This utility backfills/recalculates analyses.  Generic syntax: "
                                  + "\n\tAnalysisBackfill.exe \\\\AFServer\\AFDatabase\\pathToElement\\AFElement AnalysisNameFilter StartTime EndTime Mode"
                                  + "\n This utility supports two modes: backfill and recalc.  Backfill will fill in data gaps only.  Recalc will replace all values.  Examples:"
                                  + "\n\tAnalysisBackfill.exe \\\\AF1\\TestDB\\Plant1\\Pump1 FlowRate_*Avg '*-10d' '*' recalc"
                                  + "\n\tAnalysisBackfill.exe \\\\AF1\\TestDB\\Plant1\\Pump1 *Rollup '*-10d' '*' backfill";

            //bad input handling & help
            if (args.Length < 5 || args.Contains("?"))
            {
                Console.WriteLine(help_message);
                Environment.Exit(0);
            }

            try
            {
                //parse inputs and connect
                user_path = args[0];
                var inputs = user_path.Split('\\');
                user_serv = inputs[2];
                user_db   = inputs[3];

                //connect
                AFSystemHelper.Connect(user_serv, user_db);
                aSystem          = aSystems[user_serv];
                aDatabase        = aSystem.Databases[user_db];
                aAnalysisService = aSystem.AnalysisService;

                /* check versions.  need to write this.
                 * aSystem.ServerVersion
                 * aSystems.Version
                 * aPIServer.ServerVersion
                 */

                //find AFElements
                //will eventually include element search filter as well
                if (inputs.Length == 4)
                { //all elements in database
                    foundElements = AFElement.FindElements(aDatabase, null, null, AFSearchField.Name, true, AFSortField.Name, AFSortOrder.Ascending, 1000).ToList();
                }
                else
                { //single element
                    var prelength = user_serv.Length + user_db.Length;
                    var path1     = user_path.Substring(prelength + 4, user_path.Length - prelength - 4);
                    foundElements.Add((AFElement)AFObject.FindObject(path1, aDatabase));
                }

                //other inputs
                user_analysisfilter = args[1];
                AFTime backfillStartTime = new AFTime(args[2].Trim('\''));
                AFTime backfillEndTime   = new AFTime(args[3].Trim('\''));
                backfillPeriod = new AFTimeRange(backfillStartTime, backfillEndTime);

                //user_mode
                user_mode = args[4];
                switch (user_mode.ToLower())
                {
                case "recalc":
                    mode = AFAnalysisService.CalculationMode.DeleteExistingData;
                    break;

                case "backfill":
                    mode = AFAnalysisService.CalculationMode.FillDataGaps;
                    break;

                default:
                    Console.WriteLine("Invalid mode specified.  Supported modes: backfill, recalc");
                    Environment.Exit(0);
                    break;
                }

                Console.WriteLine("Requested backfills/recalculations:");

                foreach (AFElement elem_n in foundElements)
                {
                    //find analyses
                    String           analysisfilter = "Target:=\"" + elem_n.GetPath(aDatabase) + "\" Name:=\"" + user_analysisfilter + "\"";
                    AFAnalysisSearch analysisSearch = new AFAnalysisSearch(aDatabase, "analysisSearch", AFAnalysisSearch.ParseQuery(analysisfilter));
                    elemAnalyses = analysisSearch.FindAnalyses(0, true).ToList();

                    //print details to user
                    Console.WriteLine("\tElement: " + elem_n.GetPath().ToString()
                                      + "\n\tAnalyses (" + elemAnalyses.Count() + "):");

                    if (elemAnalyses.Count() == 0)
                    {
                        Console.WriteLine("\t\tNo analyses on this AF Element match the analysis filter.");
                    }
                    else
                    {
                        foundAnalyses.AddRange(elemAnalyses);
                        foreach (var analysis_n in elemAnalyses)
                        {
                            Console.WriteLine("\t\t{0}, {1}, Outputs:{2}", analysis_n.Name, analysis_n.AnalysisRule.Name, analysis_n.AnalysisRule.GetOutputs().Count);
                        }
                    }

                    /* to check for dependent analyses
                     * foreach (var analysis_n in foundAnalyses)
                     * {
                     *
                     * }
                     */
                }
                Console.WriteLine("\nTime range: " + backfillPeriod.ToString() + ", " + "{0}d {1}h {2}m {3}s."
                                  , backfillPeriod.Span.Days, backfillPeriod.Span.Hours, backfillPeriod.Span.Minutes, backfillPeriod.Span.Seconds);
                Console.WriteLine("Mode: " + user_mode + "=" + mode.ToString());
                //implement wait time
                Console.WriteLine("\nA total of {0} analyses will be queued for processing in 10 seconds.  Press Ctrl+C to cancel.", foundAnalyses.Count);
                DateTime beginWait = DateTime.Now;
                while (!Console.KeyAvailable && DateTime.Now.Subtract(beginWait).TotalSeconds < 10)
                {
                    Console.Write(".");
                    Thread.Sleep(250);
                }
                //no status check
                Console.WriteLine("\n\nAll analyses have been queued.\nThere is no status check after the backfill/recalculate is queued (until AF 2.9.0). Please verify by using other means.", foundAnalyses.Count);

                //queue analyses for backfill/recalc
                foreach (var analysis_n in foundAnalyses)
                {
                    response = aAnalysisService.QueueCalculation(new List <AFAnalysis> {
                        analysis_n
                    }, backfillPeriod, mode);

                    /* no status check info
                     * in AF 2.9, QueueCalculation will allow for true status checking. In AF 2.8.5, it is not possible to check.
                     * Documentation (https://techsupport.osisoft.com/Documentation/PI-AF-SDK/html/M_OSIsoft_AF_Analysis_AFAnalysisService_ToString.htm) states:
                     * This method queues the list of analyses on the analysis service to be calculated.
                     * The operation is asynchronous and returning of the method does not indicate that queued analyses were calculated.
                     * The status can be queried in the upcoming releases using the returned handle.
                     */

                    //Might be able to add a few check mechanisms using AFAnalysis.GetResolvedOutputs and the number of values in AFTimeRange
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error returned: " + ex.Message);
                Environment.Exit(0);
            }
        }
Ejemplo n.º 7
0
        public static void GetACIOutput(Service unit, string ViewerFilePath)
        {
            PISystems  piSystems = new PISystems();
            PISystem   piSystem;
            AFDatabase database;

            string error  = "";
            string error1 = "";

            Outputs objOutputUnit = null;
            CurrentOutputAtGivenLoadStep resCurrentOutputs = null;
            IdealOutputAtGivenTorque     resIdealOtpsAt90T = null, resIdealOtpsAt95T = null, resIdealOtpsAt100T = null;

            IList <PIPoint> lstPiPointForUnit = null;
            AFNamedCollectionList <AFElement> AllElements = new AFNamedCollectionList <AFElement>();
            AFValue floatingValue             = null;

            AFElement   Model          = new AFElement();
            AFAttribute ErrorArrayCode = null;

            try
            {
                piSystem = piSystems["WINOSIT3D01"];
                database = piSystem.Databases["DCPDev"];

                if (File.Exists(ViewerFilePath))
                {
                    // Trace.Write(unit.UnitName + "   :"); Trace.WriteLine(ViewerFilePath);

                    var objERCM = objERCMKernal;
                    objERCM.Reset();
                    objERCM.eRCMViewerFilename = ViewerFilePath;
                    AciModelInputs objAciInput = new AciModelInputs(unit);
                    if (objERCM.SuccessfulFileLoad)
                    {
                        if (!string.IsNullOrEmpty(objAciInput.ErrorMsg))
                        {
                            Trace.TraceError("Valid Input data not available for " + unit.UnitName + " at" + DateTime.Now);
                            return;
                        }

                        objOutputUnit = GetACIOutputObjectForUnit(unit.UnitName, unit.ServiceName);

                        if (objAciInput.Rpm < 100)
                        {
                            error1 = " RPM is less than 100. Model wouold not run for " + unit.ServiceName + " " + unit.UnitName;
                            Console.WriteLine(error1);

                            AllElements = AFElement.FindElements(database, null, null, AFSearchField.Name, true, AFSortField.Name, AFSortOrder.Ascending, 1000000000);


                            foreach (AFElement ele in AllElements)
                            {
                                if (ele.Name.Equals(unit.UnitName) && ((ele.Parent != null && ele.Parent.Name.Equals(unit.ServiceName)) || (ele.Parent.Parent != null && ele.Parent.Parent.Name.Equals(unit.ServiceName))))
                                {
                                    Model          = ele.Elements["Model"];
                                    ErrorArrayCode = Model.Attributes["ACI Error Array Code"];

                                    floatingValue = new AFValue(error1);
                                    ErrorArrayCode.Data.UpdateValue(floatingValue, AFUpdateOption.NoReplace, AFBufferOption.DoNotBuffer);
                                }
                            }

                            return;
                        }

                        objERCM.CurrentLoadStep = unit.LoadStep;
                        resCurrentOutputs       = GetCurrentOutputAtGivenLoadStep(unit.LoadStep, objAciInput, objERCM);
                        resIdealOtpsAt90T       = GetIdealOutputAtGivenTorque(unit.LoadStep, 90, objAciInput, objERCM);
                        resIdealOtpsAt95T       = GetIdealOutputAtGivenTorque(unit.LoadStep, 95, objAciInput, objERCM);
                        resIdealOtpsAt100T      = GetIdealOutputAtGivenTorque(unit.LoadStep, 100, objAciInput, objERCM);

                        objERCM.TorqueLimit     = 100;
                        objERCM.CurrentLoadStep = unit.LoadStep;
                        objERCM.ChangeOpCondition(objAciInput.PsG, objAciInput.PdG, objAciInput.Rpm,
                                                  objAciInput.Ts1, objAciInput.Ts2, objAciInput.Ts3, objAciInput.Ts4, objAciInput.Ts5, objAciInput.Ts6);

                        string ACIInputValues = "PsG:" + objAciInput.PsG + " PdG:" + objAciInput.PdG + " Rpm:" + objAciInput.Rpm + " Ts1:" +
                                                objAciInput.Ts1 + " Ts2:" + objAciInput.Ts2 + " Ts3:" + objAciInput.Ts3 + " Ts4:" + objAciInput.Ts4 + " Ts5:" + objAciInput.Ts5 + " Ts6:" + objAciInput.Ts6;
                        Trace.TraceInformation(ACIInputValues);
                        //Max Allowed Dischage Pressure
                        var MaxAllowedPd = objERCM.CalcMaxAllowedPd(objAciInput.PsG, objAciInput.Rpm, objAciInput.Ts1, objAciInput.Ts2, objAciInput.Ts3, objAciInput.Ts4, objAciInput.Ts5, objAciInput.Ts6, unit.LoadStep);
                        objERCM.ErrorArray(objERCM.CurrentLoadStep);
                        error = objERCM.FullEnglishErrors(objERCM.ErrorArray(objERCM.CurrentLoadStep), 0);

                        if (error != string.Empty)
                        {
                            Trace.TraceInformation(ACIInputValues);
                            Trace.TraceError(error);
                        }
                        error = error + error1;

                        string CurrentTorq = objERCM.CurrentTorque.ToString();
                        //Output Result
                        //objOutputUnit = GetACIOutputObjectForUnit(unit.UnitName, unit.ServiceName);//at here Error Occurs!!!
                        //Assign Value to tags
                        lstPiPointForUnit = GetOutputTagList(objOutputUnit);
                        //Update in PI Server
                        // var result = SaveOutputDataInPi(objUnit, lstPiPointForUnit, objERCM);
                        objOutputUnit.MaxAllowedDischargePressure.Value = MaxAllowedPd;

                        //Current Operating Outputs
                        objOutputUnit.LoadStep.Current.Value        = resCurrentOutputs.CurrentLoadStep;
                        objOutputUnit.LoadStep.CurrentDetails.Value = resCurrentOutputs.CurrentLoadStepDetail;
                        objOutputUnit.LoadPrediction.Current.Value  = resCurrentOutputs.CurrentLoad;
                        objOutputUnit.FlowPrediction.Current.Value  = resCurrentOutputs.CurrentFlow;
                        objOutputUnit.FuelRate.Current.Value        = resCurrentOutputs.CurrentFuelRate;

                        //Ideal Outputs at 90% Torque
                        objOutputUnit.IdealFlow90T.Value           = resIdealOtpsAt90T.IdealFlowAtGivenTorque;
                        objOutputUnit.IdealFuelRate90T.Value       = resIdealOtpsAt90T.IdealFuelRateAtGivenTorque;
                        objOutputUnit.IdealLoad90T.Value           = resIdealOtpsAt90T.IdealLoadAtGivenTorque;
                        objOutputUnit.IdealLoadStep90T.Value       = resIdealOtpsAt90T.IdealLoadStepAtGivenTorque;
                        objOutputUnit.IdealLoadStepDetail90T.Value = resIdealOtpsAt90T.IdealLoadStepDetailAtGivenTorque;
                        //Ideal Outputs at 95% Torque
                        objOutputUnit.IdealFlow95T.Value           = resIdealOtpsAt95T.IdealFlowAtGivenTorque;
                        objOutputUnit.IdealFuelRate95T.Value       = resIdealOtpsAt95T.IdealFuelRateAtGivenTorque;
                        objOutputUnit.IdealLoad95T.Value           = resIdealOtpsAt95T.IdealLoadAtGivenTorque;
                        objOutputUnit.IdealLoadStep95T.Value       = resIdealOtpsAt95T.IdealLoadStepAtGivenTorque;
                        objOutputUnit.IdealLoadStepDetail95T.Value = resIdealOtpsAt95T.IdealLoadStepDetailAtGivenTorque;
                        //Ideal Outputs at 100% Torque
                        objOutputUnit.LoadStep.Ideal.Value        = resIdealOtpsAt100T.IdealLoadStepAtGivenTorque;
                        objOutputUnit.LoadStep.IdealDetails.Value = resIdealOtpsAt100T.IdealLoadStepDetailAtGivenTorque;
                        objOutputUnit.LoadPrediction.Ideal.Value  = resIdealOtpsAt100T.IdealLoadAtGivenTorque;
                        objOutputUnit.FlowPrediction.Ideal.Value  = resIdealOtpsAt100T.IdealFlowAtGivenTorque;
                        objOutputUnit.FuelRate.Ideal.Value        = resIdealOtpsAt100T.IdealFuelRateAtGivenTorque;

                        if (resCurrentOutputs.CurrentFlow < resIdealOtpsAt100T.IdealFlowAtGivenTorque || resCurrentOutputs.CurrentLoad < resIdealOtpsAt100T.IdealLoadAtGivenTorque)
                        {
                            Console.WriteLine("Current load & Flow lower than ideal.");
                            string message = string.Format("Service Name:{0}, Unit Name:{1},Current Load:{2},Ideal Load:{3}, Current Flow:{4}, Ideal Flow: {5}",
                                                           unit.ServiceName, unit.UnitName, resCurrentOutputs.CurrentLoad, resIdealOtpsAt100T.IdealLoadAtGivenTorque, resCurrentOutputs.CurrentFlow, resIdealOtpsAt100T.IdealFlowAtGivenTorque);
                            Trace.WriteLine(message);
                            //Ideal Outputs at 90% Torque
                            objOutputUnit.IdealFlow90T.Value           = "No Data";
                            objOutputUnit.IdealFuelRate90T.Value       = "No Data";
                            objOutputUnit.IdealLoad90T.Value           = "No Data";
                            objOutputUnit.IdealLoadStep90T.Value       = "No Data";
                            objOutputUnit.IdealLoadStepDetail90T.Value = "No Data";
                            //Ideal Outputs at 95% Torque
                            objOutputUnit.IdealFlow95T.Value           = "No Data";
                            objOutputUnit.IdealFuelRate95T.Value       = "No Data";
                            objOutputUnit.IdealLoad95T.Value           = "No Data";
                            objOutputUnit.IdealLoadStep95T.Value       = "No Data";
                            objOutputUnit.IdealLoadStepDetail95T.Value = "No Data";
                            objOutputUnit.LoadStep.Ideal.Value         = "No Data";
                            objOutputUnit.LoadStep.IdealDetails.Value  = "No Data";
                            objOutputUnit.LoadPrediction.Ideal.Value   = "No Data";
                            objOutputUnit.FlowPrediction.Ideal.Value   = "No Data";
                            objOutputUnit.FuelRate.Ideal.Value         = "No Data";
                        }

                        objOutputUnit.ErrorCode.Value = error;
                        SaveOutputDataInPi(objOutputUnit, lstPiPointForUnit, objERCM, unit);
                    }
                    else
                    {
                        Trace.WriteLine("Failed to load in Viewer file!");
                    }
                }
                else
                {
                    Trace.WriteLine("File doesn't exist at " + ViewerFilePath);
                    return;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Trace.WriteLine(ex.StackTrace);
            }
        }