/// /// Copyright (c) 2013-2021 Sensus Slovensko a.s. /// using System; using System.Collections.Generic; using System.Linq; using log4net; using Config; using Config.Entities; using TBF.BenchControl.GenericDevices; using TBF.BenchControl.Operations; using TBF.Boxes; using TBF.Resources; using TBF.UiBridge; namespace TBF.BenchControl.Sequences { /// /// Sequence is a group of states that can be dynamically added to /// and removed from the state machine /// public class SequenceBase : ProcessData { private static readonly ILog log = LogManager.GetLogger(typeof(SequenceBase)); protected static readonly ILog processDataLogger = LogManager.GetLogger("ProcessData"); protected static readonly ILog allResults = LogManager.GetLogger("AllResults"); protected static readonly ILog summaryResults = LogManager.GetLogger("SummaryResults"); public const int FlowSettingTimeoutSec = 300; /// Flow setting timeout = 5 min. public const int StableMassMsrmntTimeoutSec = 300; /// Stable mass measurement timeout = 5 min. public const int CountWhenSendingRdDivCmd = 1; /// Passed to cBrd.ReadDiverterTransitionOp() public const int CountWhenReadingDiv = 3; /// Passed to cBrd.ReadDiverterTransitionOp() ///------------------------------------------------------------ /// Global static variables set only once. ///------------------------------------------------------------ public static IList FlowMeters; /// list of reference flowmeters public static IList RegulValves; /// list of regulation valves public static IList FeedingRegulValves; /// list of feeding regulation valves public static IList OutputRegulValves; /// list of output regulation valves public static IList PumpsWithFM; /// list of FM controlled pumps public static IList WaterMeters; /// list of water meters public static IList Cameras; /// list of cameras ///------------------------------------------------------------ /// Procedure related (static) variables. /// They are re-initialized when LoadProcedure() is called ///------------------------------------------------------------ public static int ReferenceFlowmetersCount; public static double[] CalibratedLtrPerRefPulse; /// Reference flowmeter coefficients public static double Qrise; public static double Qfall; ///------------------------------------------------------------ /// Test related (instance) variables. /// Created when test sequence is open. /// They persist during all repetitions of the same test ///------------------------------------------------------------ protected static BenchControl.FeedingPath inPath; protected static BenchControl.BenchPath benchPath; protected static BenchControl.OutputPath outPath; protected static BenchControl.MetersPath sensPath; protected static BenchControl.HeatMetersPath heatMetersPath; protected static TransitionSequence transitionBefore; protected static TransitionSequence transitionBetween; protected static TransitionSequence transitionAfter; /// /// Advanced information about the next test /// protected static BenchControl.FeedingPath nextInPath; protected static BenchControl.BenchPath nextBenchPath; protected static BenchControl.OutputPath nextOutPath; protected static BenchControl.MetersPath nextSensPath; protected static BenchControl.HeatMetersPath nextHeatMetersPath; protected static TransitionSequence nextTransitionBefore; protected static float nextQfrom; protected static float nextQto; protected static float nextPumpPower; protected static float nextPidCoef; protected static double nextTolerRed; protected IOperation readRegistersOp; protected IOperation queryEnd1; protected IOperation queryEnd2; protected IOperation checkUiOp; protected IOperation processDataLoggingOp; protected IOperation enduranceDataLoggingOp; protected GenericDevices.IDataEntry lastDataEntryCmpnt; /// /// Process data logging /// public void LogProcessDataTestInfo(ILog logger, string procedureName, string testName) { logger.Info(Environment.NewLine); logger.InfoFormat("{0}={1:dd.MM.yyyy HH:mm:ss} {2}={3} {4}={5} {6}={7}", Strings.Date_and_time, TestStartTime, Strings.Batch_nr, BatchRslts.Batch.BatchNr, Strings.Procedure, procedureName, Strings.Test, testName); } public void LogProcessDataHeader(ILog logger) { LogProcessDataHeader(logger, null); } public void LogProcessDataHeader(ILog logger, string sectionName) { logger.Info(Environment.NewLine); if (sectionName != null) logger.Info(sectionName); logger.Info("Time Flow TstTime Ref.cnt Ref.vol Tup Tdown Tdiv Pup Pdown Pdelta Mass VolMM Tamb Hamb Pamb Rv"); logger.Info(Environment.NewLine); } public void LogProcessData(ILog logger) { logger.InfoFormat("{0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11} {12} {13} {14} {15} {16}", DateTime.Now.ToLongTimeString(), Utils.DoubleToStr(RefFlow.Val, 4), /// flow measured by the reference flow meter in m3/h StateMachine.ControlBoard.TTime.ToString("F3"), /// test time in s StateMachine.ControlBoard.EtPulses(0), /// reference flow meter pulses count Formulas.VolumeFromPulses(StateMachine.ControlBoard.EtPulses(0), 1.0f / LtrPerRefPulse).ToString("F3"), /// volume in l TempUp, /// water temperature at the beginning of test line in degree C TempDown, /// water temperature at the end of test line in degree C TempDiv, /// water temperature at the diverter in degree C PressUp, /// water pressure at the beginning of test line in bar (= 100 kPa) PressDown, /// water pressure at the end of test line in bar (= 100 kPa) PressDelta, Mass, /// collected water mass in kg "VolMM", AmbTemp, /// ambient temperature in degree C AmbHumi, /// ambient humidity in R% AmbPress, /// ambient pressure in mbar (= 1 hPa) outPath.RegulValve.Position.ToString("F1")); /// regulation valve position in % (0=closed / 100=open) } public void LogProcessDataHeaderHeatMeters(ILog logger, string sectionName) { logger.Info(Environment.NewLine); if (sectionName != null) logger.Info(sectionName); logger.Info("Time Flow TstTime Ref.cnt Ref.vol Tup Tdown Tdiv Pup Pdown Pdelta Mass VolMM Tamb Hamb Pamb Rv Thiac1 Thiac2 Tloac1 Tloac2"); logger.Info(Environment.NewLine); } public void LogProcessDataHeatMeters(ILog logger) { logger.InfoFormat("{0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11} {12} {13} {14} {15} {16} {17} {18} {19} {20}", DateTime.Now.ToLongTimeString(), Utils.DoubleToStr(RefFlow.Val, 4), StateMachine.ControlBoard.TTime.ToString("F3"), StateMachine.ControlBoard.EtPulses(0), Formulas.VolumeFromPulses(StateMachine.ControlBoard.EtPulses(0), 1.0f / LtrPerRefPulse).ToString("F3"), TempUp, TempDown, TempDiv, PressUp, PressDown, PressDelta, Mass, "VolMM", AmbTemp, AmbHumi, AmbPress, outPath.RegulValve.Position.ToString("F1"), TempRefHi1, TempRefHi2, TempRefLo1, TempRefLo2); } /// /// Endurance data logging /// public void LogEnduranceHeader(System.IO.StreamWriter writer) { LogEnduranceHeader(writer, null); } public void LogEnduranceHeader(System.IO.StreamWriter writer, string sectionName) { writer.WriteLine(); if (sectionName != null) writer.Write(sectionName); writer.WriteLine("Time T_up T_dn Pr_up Pr_dn Flow"); } public void LogEnduranceData(System.IO.StreamWriter writer) { writer.WriteLine(string.Format("{0:dd.MM.yyyy HH:mm.ss} {1} {2} {3} {4} {5}", DateTime.Now, TempUp, TempDown, PressUp, PressDown, RefFlow)); } /// /// Used in tests in measurement loop to display remaining test time /// /// Remaining time in seconds protected void ShowRemainingTime(int remainingTime) { if (remainingTime > 60) { Bridge.OnActivity(this, string.Format("{0} ... {1} {2} {3} {4}", Strings.Test_in_progress, remainingTime / 60, "min", remainingTime % 60, Strings.sec)); } else { Bridge.OnActivity(this, string.Format("{0} ... {1} s", Strings.Test_in_progress, remainingTime)); } } protected Event DrainTheTank(IScaleOrTank tank) { return DrainTheTank(tank, new List()); } protected Event DrainTheTank(IScaleOrTank tank, IOperation extraOperation) { IList extraOperations = new List(); extraOperations.Add(extraOperation); return DrainTheTank(tank, extraOperations); } /// /// Empties the tank: opens the emptying valve and measures the weight. /// /// Valve to empty the tank /// Scale underneath the tank /// Event.Done or Event.Error protected Event DrainTheTank(IScaleOrTank tank, IList extraOperations) { IList e; bool stopped = false; Bridge.Bench2UI(ButtonsEtc.StopBtnEn); IntBox remainingTimeSec = new IntBox(); Bridge.OnActivity(this, TBF.Resources.Strings.Emptying_tank); if (tank.DrainValve2 == null) { /// /// Draining with 1 valve 'DrainValve' /// State.Create("SequenceBase : Open the drain valve") .AddOperation(checkUiOp) .AddOperation(StateMachine.ControlBoard.SetValvesOp(tank.DrainValve, null)) .AddOperations(extraOperations) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); } while (!e.Contains(Event.ValvesSet)); IOperation timer = new TimerOp(tank.EmptyTimeSec, remainingTimeSec); do { State.Create("SequenceBase : Draining the tank") .AddOperation(checkUiOp) .AddOperation(timer) .AddOperation((tank is IScale) ? (tank as IScale).ReadMassOp(ref Mass) : null) .AddOperations(extraOperations) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error)) return Event.Error; if (TestAndLogUiCmdStop(e)) { stopped = true; break; } if (e.Contains(Event.BalanceOverload)) { }; /// Tank should be emptying now /// if (!(tank is IScale)) { Bridge.OnActivity(this, string.Format("{0} ... {1} {2} {3} {4}", Strings.Emptying_tank, remainingTimeSec.Val / 60, "min", remainingTimeSec.Val % 60, Strings.sec)); } } while ((tank is IScale) && !e.Contains(Event.BalanceDone)); if (stopped) break; } while (!tank.IsEmpty() && !e.Contains(Event.TimerExpired)); } else { /// /// Draining with 2 valves: 'DrainValve' is open in the 2nd half of time, 'DrainValve2' is open all the time /// State.Create("SequenceBase : Open the drain valve") .AddOperation(checkUiOp) .AddOperation(StateMachine.ControlBoard.SetValvesOp(tank.DrainValve2, null)) .AddOperations(extraOperations) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); } while (!e.Contains(Event.ValvesSet)); /// /// 1st half /// IOperation timer1 = new TimerOp(tank.EmptyTimeSec / 2, remainingTimeSec); do { State.Create("SequenceBase : Draining the tank") .AddOperation(checkUiOp) .AddOperation(timer1) .AddOperation((tank is IScale) ? (tank as IScale).ReadMassOp(ref Mass) : null) .AddOperations(extraOperations) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error)) return Event.Error; if (TestAndLogUiCmdStop(e)) { stopped = true; break; } if (e.Contains(Event.BalanceOverload)) { }; /// Tank should be emptying now /// if (!(tank is IScale)) { Bridge.OnActivity(this, string.Format("{0} ... {1} {2} {3} {4}", Strings.Emptying_tank, (remainingTimeSec.Val + tank.EmptyTimeSec / 2) / 60, "min", (remainingTimeSec.Val + tank.EmptyTimeSec / 2) % 60, Strings.sec)); } } while ((tank is IScale) && !e.Contains(Event.BalanceDone)); if (stopped) break; } while (!tank.IsEmpty() && !e.Contains(Event.TimerExpired)); /// /// 2nd half /// if (!tank.IsEmpty()) { State.Create("SequenceBase : Open the 2nd drain valve") .AddOperation(checkUiOp) .AddOperation(StateMachine.ControlBoard.SetValvesOp(tank.DrainValve, null)) .AddOperations(extraOperations) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); } while (!e.Contains(Event.ValvesSet)); IOperation timer2 = new TimerOp(tank.EmptyTimeSec / 2, remainingTimeSec); do { State.Create("SequenceBase : Draining the tank") .AddOperation(checkUiOp) .AddOperation(timer2) .AddOperation((tank is IScale) ? (tank as IScale).ReadMassOp(ref Mass) : null) .AddOperations(extraOperations) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error)) return Event.Error; if (TestAndLogUiCmdStop(e)) { stopped = true; break; } if (e.Contains(Event.BalanceOverload)) { }; /// Tank should be emptying now /// if (!(tank is IScale)) { Bridge.OnActivity(this, string.Format("{0} ... {1} {2} {3} {4}", Strings.Emptying_tank, remainingTimeSec.Val / 60, "min", remainingTimeSec.Val % 60, Strings.sec)); } } while ((tank is IScale) && !e.Contains(Event.BalanceDone)); if (stopped) break; } while (!tank.IsEmpty() && !e.Contains(Event.TimerExpired)); } } // // Quit emptying, close the drain valve // State.Create("SequenceBase : Closing the drain valve") .AddOperation(checkUiOp) .AddOperation((tank is IScale) ? (tank as IScale).ReadMassOp(ref Mass) : null) .AddOperation(StateMachine.ControlBoard.SetValvesOp(null, tank.DrainValve)) .AddOperations(extraOperations) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error)) return Event.Error; if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop; } while (!e.Contains(Event.ValvesSet) || ((tank is IScale) && !e.Contains(Event.BalanceDone))); if (tank.DrainValve2 != null) { State.Create("SequenceBase : Closing the 2nd drain valve") .AddOperation(checkUiOp) .AddOperation((tank is IScale) ? (tank as IScale).ReadMassOp(ref Mass) : null) .AddOperation(StateMachine.ControlBoard.SetValvesOp(null, tank.DrainValve2)) .AddOperations(extraOperations) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error)) return Event.Error; if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop; } while (!e.Contains(Event.ValvesSet) || ((tank is IScale) && !e.Contains(Event.BalanceDone))); } if (tank is IScale) { State.Create("SequenceBase : Updating the mass") .AddOperation(checkUiOp) .AddOperation((tank as IScale).ReadMassOp(ref Mass)) .AddOperation(new Operations.TimerOp(5)) .AddOperations(extraOperations) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error)) return Event.Error; if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop; } while (!e.Contains(Event.BalanceDone) || !e.Contains(Event.TimerExpired)); } if (stopped) return Event.UiCmdStop; else return Event.Done; } /// /// Passed as an argument to Transition(sequence, context) /// public enum TransitionContext { PurgeBegin, BeforeTest, /// Before starting a test, paths are always applied aftr this sequence BetweenTests, /// Between two repetitions of the same test AfterTest, /// After completing a test AfterTestWithOverlap, /// After completing transition sequence paths of the next test are selected and flow setting starts PurgeEnd, Stop, } /// /// Calculates the estimate of transition sequence execution time /// /// TransitionSequence entity /// Time in seconds protected int GetTransitionTimeEst(TransitionSequence transitionSequence) { if (transitionSequence == null) return 1; return 30; /// TODO: Implement time estimte calculation } /// return SetRegValvePositionOp operations for RV-s with changed positions IList GetRegValvePositioningOps(IList regValves, float[] regValvePositions) { IList rvPosOps = new List(); if (regValves != null && regValvePositions != null) { for (int i = 0; i < Math.Min(regValves.Count, regValvePositions.Length); i++) { if (regValvePositions[i] >= 0) /// Negative value means no position change { if (RegulValves[i].IsCoax) { rvPosOps.Add(regValves[i].SetRegulValvePositionOp(regValvePositions[i], regValvePositions[i], 60)); } else { float lo = Math.Max(0, regValvePositions[i] - 3.0f); float hi = Math.Min(100.0f, regValvePositions[i] + 3.0f); rvPosOps.Add(regValves[i].SetRegulValvePositionOp(lo, hi, 60)); } } } } return rvPosOps; } /// /// Executes steps of a transition sequence /// /// TransitionSequence entity /// Calling context (see above) /// /// Event.Done Transition sequence completed OK /// Event.UiCmdStop Transition sequence interrupted by the STOP on-screen button /// Event.Error Error (e.g. RegulValveTimeOut returned by Run() of SetRegulValvePositionOp) /// protected Event Transition(TransitionSequence transitionSequence, TransitionContext context) { bool stopFlag = false; bool errorFlag = false; IList e; string message; /// switch (context) { case TransitionContext.PurgeBegin: message = Strings.Purging_i_n; break; case TransitionContext.BeforeTest: message = Strings.Test_start_sequence_i_n; break; case TransitionContext.BetweenTests: message = Strings.Between_tests_sequence_i_n; break; case TransitionContext.AfterTestWithOverlap: case TransitionContext.AfterTest: message = Strings.Test_stop_sequence_i_n; break; case TransitionContext.PurgeEnd: message = Strings.Emptying_i_n; break; case TransitionContext.Stop: message = Strings.Test_stop_sequence_i_n; break; default: message = "Transition"; break; } if (transitionSequence == null) { /// /// No transition sequence defined --> Default action /// if ((context == TransitionContext.AfterTest) || (context == TransitionContext.AfterTestWithOverlap)) { log.WarnFormat("Transition(null, context={0}), turning FM pump off and setting valves to defaults", context); if (inPath.Pump is GenericDevices.IPumpFM) (inPath.Pump as GenericDevices.IPumpFM).TurnOff(); State.Create("SequenceBase : Transition : TestEnd - Default action") .AddOperation(checkUiOp) .AddOperation(StateMachine.ControlBoard.SetValvesOp(StateMachine.DefaultValvesOpen, StateMachine.DefaultValvesClose)) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop; } while (!e.Contains(Event.ValvesSet)); } } else { /// /// Fetch and execute the transition sequence, it is guaranteed (transitionSequence != null) /// IList transitionSteps = new List(); if (StateMachine.TransitionSteps != null) { foreach (var step in StateMachine.TransitionSteps) { if ((step.TransitionSequence != null) && (step.TransitionSequence.Id == transitionSequence.Id)) { transitionSteps.Add(step); } } } int stepsCount = transitionSteps.Count; log.WarnFormat("Transition(sequence={0} ({1} steps), context={2})", transitionSequence.Name, stepsCount, context); foreach (var step in transitionSteps) { //------------------------------------------------ string activity = string.Format(message, transitionSequence.Name, step.ItemNr + 1, stepsCount); Bridge.OnActivity(this, activity); Bridge.OnMessage(this, step.Message); log.Info(activity + " " +step.Message); //------------------------------------------------ /// Prepare operation to switch valves IOperation setValvesOp = StateMachine.ControlBoard.SetValvesOp(Utils.ValvesOpen(step), Utils.ValvesClose(step)); /// Fetch the condition operation, null value is allowed if there is no condition IOperation conditionOperation = null; if (step.EndCondition != "None") { string[] fields = step.EndCondition.Split(new char[]{'~'}); if (fields.Length == 2) { ISequenceCondition seqCondition = TbfComponents.FindComponent(fields[0]) as ISequenceCondition; int condID; if ((seqCondition != null) && int.TryParse(fields[1], out condID)) { conditionOperation = seqCondition.ConditionOp(condID); } } } /// FM controlled pumps are canged imediately without using any state operations log.DebugFormat("step.PumpWithFMPcts = {0}", step.PumpWithFMPcts); float[] allFMPumpPcts = Utils.GetPumpWithFMPcts(step.PumpWithFMPcts); for (int i = 0; i < allFMPumpPcts.Length; i++) { float pwr = allFMPumpPcts[i]; if (pwr > 0) /// Negative value means no power change { PumpsWithFM[i].TurnOn(pwr); } else if (pwr == 0) { PumpsWithFM[i].TurnOff(); } } /// Get regulation valve positioning operations IList rvPosOps = GetRegValvePositioningOps(RegulValves, Utils.GetRegulValvesPositions(step.RegulValvesPct)); /// Max. one SetRegulValvePositionOp can be started or stopped in one sub-step. /// Therefore SetRegulValvePositionOp operations are added and removed to subsequent states one by one. int delay = Math.Max(2, step.Duration - rvPosOps.Count + 2); /// int lastStartedRV = -1; for (int i = 0; i < rvPosOps.Count; i++) { log.DebugFormat("SequenceBase.Transition() : Step {0} start, opening={1}, closing={2}", step.ItemNr + 1, step.ValvesOpen, step.ValvesClose); State stepStrt = State .Create(string.Format("SequenceBase.Transition() : Step {0} start, opening={1}, closing={2}", step.ItemNr + 1, step.ValvesOpen, step.ValvesClose)) .AddOperation(checkUiOp) .AddOperation(conditionOperation) .AddOperation(setValvesOp); for (int j = 0; j <= i; j++) { stepStrt.AddOperation(rvPosOps[j]); } lastStartedRV = i; stepStrt.EnterState(); e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error) || e.Contains(Event.RegulValveTimeOut)) { errorFlag = true; break; } if (TestAndLogUiCmdStop(e)) { stopFlag = true; break; } } /// Max. valaue of lastStartedRV after exitting the loop is (rvPosOps.Count - 1) if (!stopFlag && !errorFlag) { log.DebugFormat("SequenceBase.Transition() : Step {0} delay {1}s, opening={2}, closing={3}", step.ItemNr + 1, delay, step.ValvesOpen, step.ValvesClose); State stepDelay = State .Create(string.Format("SequenceBase.Transition() : Step {0} delay {1}s, opening={2}, closing={3}", step.ItemNr + 1, delay, step.ValvesOpen, step.ValvesClose)) .AddOperation(checkUiOp) .AddOperation(conditionOperation) .AddOperation(setValvesOp) .AddOperation(new TimerOp(delay)); for (int j = 0; j <= lastStartedRV; j++) { stepDelay.AddOperation(rvPosOps[j]); } stepDelay.EnterState(); bool endContitionFulfilled = false; do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error) || e.Contains(Event.RegulValveTimeOut)) { errorFlag = true; break; } if (TestAndLogUiCmdStop(e)) { stopFlag = true; break; } if (e.Contains(Event.ConditionMet)) endContitionFulfilled = true; ; /* switch (step.EndCondition) { case StepCondition.Scale1Empty: endContitionFulfilled = (StateMachine.Scale1 == null) || StateMachine.Scale1.IsEmpty(); break; case StepCondition.Scale2Empty: endContitionFulfilled = (StateMachine.Scale2 == null) || StateMachine.Scale2.IsEmpty(); break; case StepCondition.Scale3Empty: endContitionFulfilled = (StateMachine.Scale3 == null) || StateMachine.Scale3.IsEmpty(); break; case StepCondition.AllScalesEmpty: endContitionFulfilled = ((StateMachine.Scale1 == null) || StateMachine.Scale1.IsEmpty()) && ((StateMachine.Scale2 == null) || StateMachine.Scale2.IsEmpty()) && ((StateMachine.Scale3 == null) || StateMachine.Scale3.IsEmpty()); break; } */ } while (e.Contains(Event.ValvesBusy) || (!endContitionFulfilled && e.Contains(Event.TimerBusy) && !e.Contains(Event.Next))); } for (int first = 1; first <= lastStartedRV; first++) { log.DebugFormat("SequenceBase.Transition() : Step {0} stop, opening={1}, closing={2}", step.ItemNr + 1, step.ValvesOpen, step.ValvesClose); State stepStop = State .Create(string.Format("SequenceBase.Transition() : Step {0} stop, opening={1}, closing={2}", step.ItemNr + 1, step.ValvesOpen, step.ValvesClose)) .AddOperation(checkUiOp) .AddOperation(conditionOperation) .AddOperation(setValvesOp); for (int j = first; j <= lastStartedRV; j++) { stepStop.AddOperation(rvPosOps[j]); } stepStop.EnterState(); e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error) || e.Contains(Event.RegulValveTimeOut)) { errorFlag = true; } if (TestAndLogUiCmdStop(e)) { stopFlag = true; } } if (errorFlag || stopFlag) break; } Bridge.OnMessage(this, string.Empty); /// Clear the last step message } /// /// Do this after executing the transition sequence /// if (context == TransitionContext.Stop || errorFlag || stopFlag) { log.ErrorFormat("Transition({0}, context={1}) errorFlag={2} stopFlag={3} ... stoppng all pumps off", (transitionSequence != null) ? transitionSequence.Name : "null", context, errorFlag, stopFlag); /// /// On error or when STOP pressed /// foreach (var fmPump in PumpsWithFM) fmPump.TurnOff(); if (inPath != null) { /// /// Stop the pump /// State.Create("SequenceBase.Transition() : Test stopped -> Stopping the pump") .AddOperation(checkUiOp) .AddOperation(StateMachine.ControlBoard.SetValvesOp(null, inPath.Pump)) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error)) return Event.Error; } while (!e.Contains(Event.ValvesSet)); } } else if (context == TransitionContext.BeforeTest && inPath != null && benchPath != null && outPath != null) { log.WarnFormat("Transition(any, context={0}), setting the required route before a test", context); /// /// Always set route at the beginning of this test /// Event evnt = PerformSteps(GenericDevices.ValveBase.Merge(inPath.ValvesOpen, benchPath.ValvesOpen, outPath.ValvesOpen), GenericDevices.ValveBase.Merge(inPath.ValvesClose, benchPath.ValvesClose, outPath.ValvesClose), GetRegValvePositioningOps(OutputRegulValves, outPath.RegulValvesPct), "SequenceBase : Transition : TestStart - Default action"); if (evnt == Event.Error || evnt == Event.UiCmdStop) return evnt; } else if (context == TransitionContext.AfterTestWithOverlap && nextInPath != null && nextBenchPath != null && nextOutPath != null) { log.WarnFormat("Transition(., context={0}), overlapped action (next flow regulation)", context); /// /// Set route for the next test /// Event evnt = PerformSteps(GenericDevices.ValveBase.Merge(nextInPath.ValvesOpen, nextBenchPath.ValvesOpen, nextOutPath.ValvesOpen), GenericDevices.ValveBase.Merge(nextInPath.ValvesClose, nextBenchPath.ValvesClose, nextOutPath.ValvesClose), GetRegValvePositioningOps(OutputRegulValves, outPath.RegulValvesPct), "SequenceBase : AfterTestWithOverlap : Default action"); /// Set PID coefficient, etc. int[] filters = new int[] { 0, 0, 0, 0, 0, 0, 0, 0 }; StateMachine.ControlBoard.SetFiltersPidShortPulses(filters, nextPidCoef, (nextTolerRed == 0) ? 0 : 1); /// Set pump power if (nextInPath.Pump is GenericDevices.IPumpFM) (nextInPath.Pump as GenericDevices.IPumpFM).TurnOn(nextPumpPower); //------------------------------------------------ Bridge.OnActivity(this, Strings.Setting_the_flow); //------------------------------------------------ /// Set flow for the next test State.Create(string.Format("SequenceBase : AfterTestWithOverlap - Setting the flow to {0} - {1} m3/h", nextQfrom, nextQto)) .AddOperation(checkUiOp) .AddOperation(nextOutPath.RegulValve.SetFlowAndMeasureOp(nextOutPath.FlowMeter, nextQfrom, nextQto, RefFlow, FlowSettingTimeoutSec, 0)) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.OpArgumentError)) return Event.Error; if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop; if (e.Contains(Event.RegulValveTimeOut)) { Bridge.OnError(this, Strings.Flow_adjustment_failed); return Event.UiCmdStop; } } while (!e.Contains(Event.Busy) && !e.Contains(Event.FlowReached)); } if (errorFlag) return Event.Error; else if (stopFlag) return Event.UiCmdStop; else return Event.Done; } Event PerformSteps(IList valvesToOpen, IList valvesToClose, IList rvPosOps, string stateTitle) { bool stopFlag = false; bool errorFlag = false; IList e; IOperation setValvesOp = StateMachine.ControlBoard.SetValvesOp(valvesToOpen, valvesToClose); int lastStartedRV = -1; for (int i = 0; i < rvPosOps.Count; i++) { State stepStrt = State.Create(stateTitle) .AddOperation(checkUiOp) .AddOperation(setValvesOp); for (int j = 0; j <= i; j++) stepStrt.AddOperation(rvPosOps[j]); lastStartedRV = i; stepStrt.EnterState(); e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error) || e.Contains(Event.RegulValveTimeOut)) { errorFlag = true; break; } if (TestAndLogUiCmdStop(e)) { stopFlag = true; break; } } /// Max. valaue of lastStartedRV after exitting the loop is (rvPosOps.Count - 1) if (!stopFlag && !errorFlag) { State stepRegul = State.Create(stateTitle) .AddOperation(checkUiOp) .AddOperation(setValvesOp); for (int j = 0; j <= lastStartedRV; j++) stepRegul.AddOperation(rvPosOps[j]); stepRegul.EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error) || e.Contains(Event.RegulValveTimeOut)) { errorFlag = true; break; } if (TestAndLogUiCmdStop(e)) { stopFlag = true; break; } } while (e.Contains(Event.ValvesBusy) && !e.Contains(Event.Next)); } for (int first = 1; first <= lastStartedRV; first++) { State stepStop = State.Create(stateTitle) .AddOperation(checkUiOp) .AddOperation(setValvesOp); for (int j = first; j <= lastStartedRV; j++) stepStop.AddOperation(rvPosOps[j]); stepStop.EnterState(); e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error) || e.Contains(Event.RegulValveTimeOut)) { errorFlag = true; } if (TestAndLogUiCmdStop(e)) { stopFlag = true; } } if (stopFlag) return Event.UiCmdStop; if (errorFlag) return Event.Error; return Event.Done; } /// /// Opens a modeless dialog for entering data at the beginning of a procedure (serial numbers) /// /// true = OK, false = stop pressed protected bool OpenCycleBeginForm() { lastDataEntryCmpnt = TbfComponents.FindComponent(StateMachine.Procedure.DataEntry) as GenericDevices.IDataEntry; if (lastDataEntryCmpnt is IHasCycleBeginForm) { Bridge.OnActivity(this, Strings.Enter_water_meter_data); State.Create("MainSeq : Enter begin data") .AddPermanentOperation((lastDataEntryCmpnt as IHasCycleBeginForm).ShowCycleBeginFormOp()) .AddOperation(checkUiOp) .EnterState(); if (TestAndLogUiCmdStop(StateMachine.WaitRunDevsRunOps())) return false; /// Return false when STOP pressed } return true; /// OK (=either a cycle beginning form is open or DataEntry component is not IHasCycleBeginForm) } /// /// Waits until a modeless dialog for entering data at the beginnig of a procedure is closed. /// This function is typically called at the end of the first test of the procedure. /// /// false = OK, true = stop pressed protected UIFlowControl WaitBeginFormClosed() { GenericDevices.IDataEntry dataEntryCmpnt = TbfComponents.FindComponent(StateMachine.Procedure.DataEntry) as GenericDevices.IDataEntry; bool stopPressed = false; /// true when STOP button pressed if (dataEntryCmpnt is IHasCycleBeginForm) { IList e; /// /// Wait until modeless form is closed by the user if it is stil open /// if ( State.LastEvents.Contains(Event.ModelessFormIsOpen)) { State.Create("MainSeq : Wait until the entry form is closed") .AddOperation(checkUiOp) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (TestAndLogUiCmdStop(e)) { stopPressed = true; break; } } while (!e.Contains(Event.ModelessFormClosed)); } /// /// A state without any dataEntryCmpnt operation so that Stop() when entering /// this state and Start() when entering the following state are executed. /// State.Create("MainSeq : Stopping modeless form") .AddOperation(checkUiOp) .RemovePermanentOperation(dataEntryCmpnt as IOperation) .EnterState(); e = StateMachine.WaitRunDevsRunOps(); if (TestAndLogUiCmdStop(e)) { stopPressed = true; } } return stopPressed ? UIFlowControl.Stop : UIFlowControl.Continue; } /// /// Forces closing of a modeless dialog for entering data at the beginnig of a procedure. /// This function is typically called before starting a new cycle /// in case previous cycle was aborted. /// protected void CloseBeginForm() { if (StateMachine.Procedure == null || StateMachine.Procedure.DataEntry == null) return; GenericDevices.IDataEntry dataEntryCmpnt = TbfComponents.FindComponent(StateMachine.Procedure.DataEntry) as GenericDevices.IDataEntry; if ((dataEntryCmpnt is IHasCycleBeginForm) && (State.LastEvents.Contains(Event.ModelessFormIsOpen) || State.LastEvents.Contains(Event.ModelessFormClosed))) { IList e; /// A state without any dataEntryCmpnt operation so that Stop() when entering /// this state and Start() when entering the following state are executed. State.Create("MainSeq : Stopping modeless form") .RemovePermanentOperation(dataEntryCmpnt as IOperation) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); } while (e.Contains(Event.ModelessFormIsOpen)); } } protected Event SetFlowEtc(Test test, IFlowMeter flowMeter, IRegulValve regulValve, IValve pump, IValve stopBFValve, IList extraOperations, bool doNotWait) { IList e; Event retVal = Event.Done; if (pump is GenericDevices.IPumpFM) (pump as GenericDevices.IPumpFM).TurnOn(test.PumpPower); /// State.Create(string.Format("{0}({1}) : Starting the pump", test.Method, test.Name)) .AddOperation(checkUiOp) .AddOperations(extraOperations) .AddOperation(pump != null ? StateMachine.ControlBoard.SetValvesOp(pump, null) : null) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); //Bridge.OnProcessData(this, new ProcessDataEventArgs(test, repetitionNr, Config.Entities.Progress.FlowSetting)); //Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetitionNr, Config.Entities.Progress.FlowSetting)); if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop; if (e.Contains(Event.Error)) return Event.Error; } while (e.Contains(Event.ValvesBusy) /* || !e.Contains(Event.AllPositionsReached)*/); if (test.TimePump2StartV > 0) { State.Create(string.Format("{0}({1}) : Waiting after the pump started", test.Method, test.Name)) .AddOperation(checkUiOp) .AddOperation(new Operations.TimerOp(test.TimePump2StartV)) .AddOperations(extraOperations) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); //Bridge.OnProcessData(this, new ProcessDataEventArgs(test, repetitionNr, Config.Entities.Progress.FlowSetting)); //Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetitionNr, Config.Entities.Progress.FlowSetting)); if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop; } while (!e.Contains(Event.TimerExpired)); } if (stopBFValve != null) { State.Create(string.Format("{0}({1}) : Opening the stop backflow valve", test.Method, test.Name)) .AddOperation(checkUiOp) .AddOperation(StateMachine.ControlBoard.SetValvesOp(stopBFValve, null)) .AddOperations(extraOperations) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop; if (e.Contains(Event.Error)) return Event.Error; } while (!e.Contains(Event.ValvesSet)); } if (test.TimeBeforeFlow > 0) { State.Create(string.Format("{0}({1}) : Waiting before flow setting process starts", test.Method, test.Name)) .AddOperation(checkUiOp) .AddOperation(new Operations.TimerOp(test.TimeBeforeFlow)) .AddOperations(extraOperations) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); //Bridge.OnProcessData(this, new ProcessDataEventArgs(test, repetitionNr, Config.Entities.Progress.FlowSetting)); //Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetitionNr, Config.Entities.Progress.FlowSetting)); if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop; } while (!e.Contains(Event.TimerExpired)); } //------------------------------------------------ Bridge.OnActivity(this, Strings.Setting_the_flow); //------------------------------------------------ State.Create(string.Format("{0}({1}) : Setting the flow", test.Method, test.Name)) .AddOperation(checkUiOp) .AddOperation(doNotWait ? regulValve.SetFlowAndMeasureOp(flowMeter, test.Qfrom, test.Qto, RefFlow, FlowSettingTimeoutSec, 0) : regulValve.SetFlowOp(flowMeter, test.Qfrom, test.Qto, RefFlow, FlowSettingTimeoutSec)) .AddOperations(extraOperations) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); //Bridge.OnProcessData(this, new ProcessDataEventArgs(test, repetitionNr, Config.Entities.Progress.FlowSetting)); //Bridge.OnTestProgress(this, new TestProgressEventArgs(test, repetitionNr, Config.Entities.Progress.FlowSetting)); if (e.Contains(Event.OpArgumentError)) return Event.OpArgumentError; if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop; if (e.Contains(Event.RegulValveTimeOut)) { Bridge.OnError(this, Strings.Flow_adjustment_failed); return Event.RecoverableError; } if (e.Contains(Event.Next)) return Event.Done; } while (!(e.Contains(Event.FlowReached) || (doNotWait && e.Contains(Event.Busy)))); /// Stay in the loop while e.Contains(Event.Starting) return retVal; } /// /// Main loop where measurements are collected. /// /// false = a flow setting or a switching flow detection, true = measurement /// Event.MeasurementCompleted, Event.UiCmdStop, Event.Error or Event.Done protected Event ReadRegistersTempPressAmbient(IList measureOperations, bool realTest) { IList e; State.Create("Read water meters") .AddOperation(checkUiOp) .AddOperations(measureOperations) .AddOperation(readRegistersOp) .AddOperation(benchPath.TempMtrUp == null ? null : benchPath.TempMtrUp.ReadTempOp(ref TempUp)) .AddOperation(benchPath.TempMtrDown == null ? null : benchPath.TempMtrDown.ReadTempOp(ref TempDown)) .AddOperation(outPath.TempDiv == null ? null : outPath.TempDiv.ReadTempOp(ref TempDiv)) .AddOperation(benchPath.PressMtrUp == null ? null : benchPath.PressMtrUp.ReadPressureOp(ref PressUp)) .AddOperation(benchPath.PressMtrDown == null ? null : benchPath.PressMtrDown.ReadPressureOp(ref PressDown)) .AddOperation(benchPath.PressMtrDelta == null ? null : benchPath.PressMtrDelta.ReadPressureOp(ref PressDelta)) .AddOperation(heatMetersPath == null ? null : heatMetersPath.TMeterRefWarm1.ReadTempOp(ref TempRefHi1)) .AddOperation(heatMetersPath == null ? null : heatMetersPath.TMeterRefWarm2.ReadTempOp(ref TempRefHi2)) .AddOperation(heatMetersPath == null ? null : heatMetersPath.TMeterRefCold1.ReadTempOp(ref TempRefLo1)) .AddOperation(heatMetersPath == null ? null : heatMetersPath.TMeterRefCold2.ReadTempOp(ref TempRefLo2)) .AddOperation((realTest && (outPath.Scale is IScale)) ? (outPath.Scale as IScale).ReadMassOp(ref Mass) : null) //.AddOperation(realTest ? (ticTac ? queryEnd1 : queryEnd2) : null) .AddOperation(realTest ? queryEnd1 : null) .AddOperation(realTest ? processDataLoggingOp : null) .EnterState(); do { e = StateMachine.WaitRunDevsRunOps(); if (e.Contains(Event.Error)) return Event.Error; if (TestAndLogUiCmdStop(e)) return Event.UiCmdStop; if (e.Contains(Event.MeasurementCompleted) || e.Contains(Event.Next)) return Event.MeasurementCompleted; } while ( (realTest && (outPath.Scale is IScale) && !e.Contains(Event.BalanceDone)) || !e.Contains(Event.ReadAllRegistersDone)); return Event.Done; } /// /// Update temperature, pressure, water density and ambient values /// including their statistics in the test results structure. /// /// Test results protected void UpdateTempPressDensAmb(Results.Entities.TestRslt tstRslt) { tstRslt.AmbTempMean = (float)AmbTempStat.Average; tstRslt.AmbTempStart = (float)AmbTempStat.First; tstRslt.AmbTempEnd = (float)AmbTempStat.Last; tstRslt.AmbTempMin = (float)AmbTempStat.Min; tstRslt.AmbTempMax = (float)AmbTempStat.Max; tstRslt.AmbPressMean = (float)AmbPressStat.Average; tstRslt.AmbPressStart = (float)AmbPressStat.First; tstRslt.AmbPressEnd = (float)AmbPressStat.Last; tstRslt.AmbPressMin = (float)AmbPressStat.Min; tstRslt.AmbPressMax = (float)AmbPressStat.Max; tstRslt.AmbHumiMean = (float)AmbHumiStat.Average; tstRslt.AmbHumiStart = (float)AmbHumiStat.First; tstRslt.AmbHumiEnd = (float)AmbHumiStat.Last; tstRslt.AmbHumiMin = (float)AmbHumiStat.Min; tstRslt.AmbHumiMax = (float)AmbHumiStat.Max; tstRslt.PressUpMean = (float)PressUpStat.Average; tstRslt.PressUpStart = (float)PressUpStat.First; tstRslt.PressUpEnd = (float)PressUpStat.Last; tstRslt.PressUpMin = (float)PressUpStat.Min; tstRslt.PressUpMax = (float)PressUpStat.Max; tstRslt.PressDownMean = (float)PressDownStat.Average; tstRslt.PressDownStart = (float)PressDownStat.First; tstRslt.PressDownEnd = (float)PressDownStat.Last; tstRslt.PressDownMin = (float)PressDownStat.Min; tstRslt.PressDownMax = (float)PressDownStat.Max; tstRslt.PressDeltaMean = (float)PressDeltaStat.Average; tstRslt.PressDeltaStart = (float)PressDeltaStat.First; tstRslt.PressDeltaEnd = (float)PressDeltaStat.Last; tstRslt.PressDeltaMin = (float)PressDeltaStat.Min; tstRslt.PressDeltaMax = (float)PressDeltaStat.Max; tstRslt.ConductMean = (float)ConductStat.Average; tstRslt.ConductStart = (float)ConductStat.First; tstRslt.ConductEnd = (float)ConductStat.Last; tstRslt.ConductMin = (float)ConductStat.Min; tstRslt.ConductMax = (float)ConductStat.Max; tstRslt.TempUpMean = (float)TempUpStat.Average; tstRslt.TempUpStart = (float)TempUpStat.First; tstRslt.TempUpEnd = (float)TempUpStat.Last; tstRslt.TempUpMin = (float)TempUpStat.Min; tstRslt.TempUpMax = (float)TempUpStat.Max; tstRslt.TempDownMean = (float)TempDownStat.Average; tstRslt.TempDownStart = (float)TempDownStat.First; tstRslt.TempDownEnd = (float)TempDownStat.Last; tstRslt.TempDownMin = (float)TempDownStat.Min; tstRslt.TempDownMax = (float)TempDownStat.Max; tstRslt.TempDivMean = (float)TempDivStat.Average; tstRslt.TempDivStart = (float)TempDivStat.First; tstRslt.TempDivEnd = (float)TempDivStat.Last; tstRslt.TempDivMin = (float)TempDivStat.Min; tstRslt.TempDivMax = (float)TempDivStat.Max; tstRslt.DensityIn = Formulas.WaterDensityFromTempPress(tstRslt.TempUpMean, tstRslt.PressUpMean); tstRslt.DensityDiv = Formulas.WaterDensityFromTempPress(tstRslt.TempDivMean, 0); tstRslt.DensityLine = Formulas.WaterDensityFromTempPress((tstRslt.TempUpMean + tstRslt.TempDownMean) / 2, (tstRslt.PressUpMean + tstRslt.PressDownMean) / 2); } protected string TestResult2CsvLine(string testName, int part) { Results.Entities.TestRslt tstRslt = ProcessData.BatchRslts.GetTestRslt(testName, part); if (tstRslt == null) return string.Empty; return TestResult2CsvLine(tstRslt); } protected string TestResult2CsvLine(Results.Entities.TestRslt tstRslt) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); try { bool isPMaxTest = tstRslt.IsPMaxTest(); bool isStartStop = tstRslt.IsStartStop(); bool isDiverter = tstRslt.IsDiverter(); bool isVolumeMethod = tstRslt.IsVolumeMethod(); sb.Append(tstRslt.StartTime); /// A sb.Append(";"); sb.Append(tstRslt.Batch.BatchNr); /// B /// Test information, target values, etc. sb.Append(";"); sb.Append(tstRslt.Name()); /// C sb.Append(";"); sb.Append(tstRslt.Repeats()); /// D sb.Append(";"); sb.Append(tstRslt.RepetitionNr); /// E sb.Append(";"); sb.Append(tstRslt.Method()); /// F sb.Append(";"); sb.Append(tstRslt.TargetVolume()); /// G sb.Append(";"); sb.Append(tstRslt.Qfrom()); /// H sb.Append(";"); sb.Append(tstRslt.Qto()); /// I sb.Append(";"); sb.Append(tstRslt.ErrLimLo() + tstRslt.ErrLimMargin()); /// J sb.Append(";"); sb.Append(tstRslt.ErrLimHi() - tstRslt.ErrLimMargin()); /// K sb.Append(";"); sb.AppendFormat("{0:F1}", tstRslt.TempLimLo()); /// L sb.Append(";"); sb.AppendFormat("{0:F1}", tstRslt.TempLimHi()); /// M sb.Append(";"); sb.Append("0"); /// N sb.Append(";"); sb.Append("16"); /// O sb.Append(";"); sb.Append(tstRslt.RefFlowmeter()); /// P sb.Append(";"); sb.AppendFormat("{0:F4}", Formulas.DistilledWaterDensityFromTemp(tstRslt.AmbTempMean)); /// Q [kg/m3] hustota vody pri teplote okolia z priemernej teploty okolia bez korekcie na realnu hustotu vody sb.Append(";"); sb.Append((tstRslt.Components != null) ? tstRslt.Components.Scale : string.Empty); /// R /// Ambient sb.Append(";"); sb.AppendFormat("{0:F1}", Units.ConvertTo(Unit.C, tstRslt.AmbTempStart)); /// S [°C] sb.Append(";"); sb.AppendFormat("{0:F0}", Units.ConvertTo(Unit.mbar, tstRslt.AmbPressStart)); /// T [mbar] sb.Append(";"); sb.AppendFormat("{0:F1}", Units.ConvertTo(Unit.RPct, tstRslt.AmbHumiStart)); /// U [R%] /// Pressure sb.Append(";"); sb.AppendFormat("{0:F0}", Units.ConvertTo(Unit.kPa, tstRslt.PressUpMean)); /// V [kPa] sb.Append(";"); sb.AppendFormat("{0:F0}", Units.ConvertTo(Unit.kPa, tstRslt.PressDownMean)); /// W [kPa] sb.Append(";"); sb.AppendFormat("{0:F1}", Units.ConvertTo(Unit.kPa, tstRslt.PressDeltaMean)); /// X [kPa] sb.Append(";"); sb.AppendFormat("{0:F0}", Units.ConvertTo(Unit.kPa, tstRslt.PressUpStart)); /// Y [kPa] sb.Append(";"); sb.AppendFormat("{0:F0}", Units.ConvertTo(Unit.kPa, tstRslt.PressDownStart)); /// Z [kPa] sb.Append(";"); sb.AppendFormat("{0:F1}", Units.ConvertTo(Unit.kPa, tstRslt.PressDeltaStart)); /// AA [kPa] sb.Append(";"); sb.AppendFormat("{0:F0}", Units.ConvertTo(Unit.kPa, tstRslt.PressUpEnd)); /// AB [kPa] sb.Append(";"); sb.AppendFormat("{0:F0}", Units.ConvertTo(Unit.kPa, tstRslt.PressDownEnd)); /// AC [kPa] sb.Append(";"); sb.AppendFormat("{0:F1}", Units.ConvertTo(Unit.kPa, tstRslt.PressDeltaEnd)); /// AD [kPa] /// Temperature sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.TempUpMean)); /// AE [°C] sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.TempDownMean)); /// AF [°C] sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.TempDivMean)); /// AG [°C] sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.Custom1)); /// AH [°C] T hi mean sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.Custom6)); /// AI [°C] T lo mean sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.TempUpStart)); /// AJ [°C] sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.TempDownStart)); /// AK [°C] sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.TempDivStart)); /// AL [°C] sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.Custom2)); /// AM [°C] T hi start sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.Custom7)); /// AN [°C] T lo start sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.TempUpEnd)); /// AO [°C] sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.TempDownEnd)); /// AP [°C] sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.TempDivEnd)); /// AQ [°C] sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.Custom3)); /// AR [°C] T hi end sb.Append(";"); sb.Append(Units.ConvertTo(Unit.C, tstRslt.Custom8)); /// AS [°C] T lo end /// Mass sb.Append(";"); sb.Append(tstRslt.MassStartRaw); /// AT [kg] sb.Append(";"); sb.Append(tstRslt.MassStart); /// AU [kg] sb.Append(";"); sb.Append(tstRslt.MassEndRaw); /// AV [kg] sb.Append(";"); sb.Append(tstRslt.MassEnd); /// AW [kg] sb.Append(";"); sb.Append(tstRslt.MassEnd - tstRslt.MassStart); /// AX [kg] /// Density and buoyancy sb.Append(";"); sb.Append(tstRslt.DensityDiv); /// AY [kg/m3] sb.Append(";"); sb.Append((tstRslt.TempUpMean + tstRslt.TempDownMean) / 2); /// AZ [°C] Tline ... priemerna teplota v linii sb.Append(";"); sb.Append(tstRslt.DensityLine); /// BA [kg/m3] sb.Append(";"); sb.Append(" "); /// BB d_air: Hustota vzduchu: Sheet1 - K9 sb.Append(";"); sb.Append(tstRslt.Buoyancy); /// BC Buoyancy: Sheet1 - X9 sb.Append(";"); sb.Append(Config.Formulas.RealDensity()); /// BD sb.Append(";"); sb.Append(Config.Formulas.AtTemperature()); /// BE sb.Append(";"); sb.Append(tstRslt.FlowMax); /// BF pipe expansion: teraz vynechat sb.Append(";"); sb.Append(tstRslt.FlowMin); /// BG [kg/h] Qm sb.Append(";"); sb.Append(tstRslt.FlowVolume); /// BH [l/h] Qv sb.Append(";"); sb.Append(tstRslt.VolumeCTV); /// BI [l] Vet .... komercne prava hodnota objemu - podla vahy sb.Append(";"); sb.Append(tstRslt.VolumeMaster); /// BJ [l] Velm ... objem podla etalonu (Prolonged: objem do vahy podla impulzov hradlovanych klapkou) sb.Append(";"); sb.Append(" "); /// BK [l] Vmass .. objem podla druheho etalonu / prietokomeru pred tratou (teraz vynechavame) sb.Append(";"); sb.Append(tstRslt.TestTime); /// BL [s] sb.Append(";"); sb.Append(isVolumeMethod ? Config.Formulas.ErrorFromVolumes(tstRslt.ConstMasterCorr, tstRslt.ConstMasterRaw) : tstRslt.ErrorMaster); /// BM [%] Eelm .... chyba etalonu voci komercne pravej hodnote sb.Append(";"); sb.Append(" "); /// BN [%] Emass ... chyba druheho etalonu voci komercne pravej hodnote (teraz vynechavame) sb.Append(";"); sb.Append((tstRslt.ConstMasterRaw != 0) ? (1 / tstRslt.ConstMasterRaw) : 0); /// BO [pls/l] Const.MID .. konstanta etalonu sb.Append(";"); sb.Append(" "); /// BP [pls/l] Const.MA ... konstanta druheho etalonu sb.Append(";"); sb.AppendFormat("{0:F0}", isDiverter ? 1000.0F * tstRslt.DiverterStart : 0); /// BQ [ms] Diverter start time sb.Append(";"); sb.AppendFormat("{0:F0}", isDiverter ? 1000.0F * tstRslt.DiverterEnd : 0); /// BR [ms] Diverter end time sb.Append(";"); sb.AppendFormat("{0:F0}", isStartStop ? 1000.0F * tstRslt.DiverterStart : 0); /// BS [ms] Start valve open time sb.Append(";"); sb.AppendFormat("{0:F0}", isStartStop ? 1000.0F * tstRslt.DiverterEnd : 0); /// BT [ms] Start valve close time sb.Append(";"); sb.Append(tstRslt.TempUpMax); /// BU [°C] sb.Append(";"); sb.Append(tstRslt.TempDownMax); /// BV [°C] sb.Append(";"); sb.Append(tstRslt.TempUpMin); /// BW [°C] sb.Append(";"); sb.Append(tstRslt.TempDownMin); /// BX [°C] sb.Append(";"); sb.Append(isPMaxTest ? tstRslt.TestTime : 0); /// BY [s] Duration of the pressure test sb.Append(";"); sb.AppendFormat("{0:F1}", Units.ConvertTo(Unit.C, tstRslt.AmbTempEnd)); /// BZ [°C] sb.Append(";"); sb.AppendFormat("{0:F0}", Units.ConvertTo(Unit.mbar, tstRslt.AmbPressEnd)); /// CA [mbar] sb.Append(";"); sb.AppendFormat("{0:F1}", Units.ConvertTo(Unit.RPct, tstRslt.AmbHumiEnd)); /// CB [R%] sb.Append(";"); sb.Append(tstRslt.PulsesMaster); /// CC Celkovy pocet et. pulzov skusky (Prolonged : do vahy) //sb.Append(";"); sb.Append((tstRslt.TotalPulsesMstr != 0) ? tstRslt.TotalPulsesMstr.ToString() : " "); /// CD - '' - pre druhy (Prolonged : celkovy pocet) sb.Append(";"); sb.Append(1000 * tstRslt.TestTimeCorrection); /// CD [ms] Diverter test time correction for (int i = 0; i < ProcessData.BatchRslts.WMPositionsCount; i++) { if (ProcessData.BatchRslts.Batch.WaterMeters != null && ProcessData.BatchRslts.Batch.WaterMeters.Count > i && ProcessData.BatchRslts.Batch.WaterMeters[i] != null && !ProcessData.BatchRslts.Batch.WaterMeters[i].Disabled) { if (!ProcessData.BatchRslts.Batch.WaterMeters[i].Compound() && !ProcessData.BatchRslts.Batch.WaterMeters[i].HeatMeter()) { /// If this is a single meter Results.Entities.MeterTestRslt mtrRslt = ProcessData.BatchRslts.GetMeterTestRslt(tstRslt.Name(), i, CompoundMeterId.Single); if (mtrRslt != null) { bool isCamera = (mtrRslt.RegReaderType == (int)RegisterReaderType.Camera); sb.Append(";"); sb.Append(ProcessData.BatchRslts.Batch.WaterMeters[i].SerialNr);/// CE WM Ser.No. sb.Append(";"); sb.Append(mtrRslt.VolumeStart); /// CF WM Vstart - pociatocny stav pri pevnom starte alebo zachyteny pri data streame sb.Append(";"); sb.Append(mtrRslt.VolumeEnd); /// CG WM Vend - konecny stav pri pevnom starte alebo zachyteny pri data streame sb.Append(";"); sb.Append(mtrRslt.VolumeMeter); /// CH WM Vmer - objem namerany vodomerom sb.Append(";"); sb.Append(mtrRslt.VolumeRef); /// CI WM Vref - objem namerany stanicou sb.Append(";"); sb.Append(mtrRslt.Error); /// CJ WM Emt - chyba vodomerom nameraneho objemu #if IPERL sb.Append(";"); sb.Append(ProcessData.BatchRslts.Batch.WaterMeters[i].CalibFactor); /// CK iPerl calibration factor used during the test / ... #else sb.Append(";"); sb.Append(" "); /// CK nechat prazdne #endif sb.Append(";"); sb.Append(mtrRslt.PulsesMeter); /// CL WM Np met - pocet impulzov zo skusaneho meradla sb.Append(";"); sb.Append(mtrRslt.PulsesMaster); /// CM WM Np elm - pocet impulzov etalonu pocas merania pre prislusny vodomer sb.Append(";"); sb.Append(mtrRslt.TestTime); /// CN WM Tmet - cas merania (obmedzany pri synchro skuske) sb.Append(";"); sb.Append(mtrRslt.Passed ? "OK" : "NOK"); /// CO WM Vysledok (t.j. ci je v hraniciach chyb) - OK/NOK #if IPERL sb.Append(";"); sb.Append(mtrRslt.WaterMeter.Q2CorrRL); /// CP iPerl Q2 correction factor used during the test / AN value - hodnota z analogoveho prevodnika #else sb.Append(";"); sb.Append(mtrRslt.PulsesPerLiter); /// CP Pulses per liter #endif sb.Append(";"); sb.Append(isCamera ? mtrRslt.VolumeStart * mtrRslt.PulsesPerLiter /// CQ WM Phi_start (pri hodnotach z kamery) : ProcessData.BatchRslts.Batch.WaterMeters[i].WMPosition); /// CQ WMPosition (normalne) sb.Append(";"); sb.Append(isCamera ? mtrRslt.VolumeEnd * mtrRslt.PulsesPerLiter /// CR WM Phi_end (pri hodnotach z kamery) : 0); /// CR not used/spare (normalne) sb.Append(";"); sb.Append(mtrRslt.TimestampStart); /// CS WM Time_start - ' ' - sb.Append(";"); sb.Append(mtrRslt.TimestampEnd); /// CT WM Time_end - ' ' - sb.Append(";"); sb.Append(isCamera ? mtrRslt.PulsesPerLiter : 0); /// CU WM Degree per liter sb.Append(";"); sb.Append(0); /// CV Analog out 1 (max mA) sb.Append(";"); sb.Append(0); /// CW Analog out 2 (V) sb.Append(";"); sb.Append(0); /// CX Analog out 3 (min mA) sb.Append(";"); sb.Append(0); /// CY Analog out 4 (max Q) } } else if (ProcessData.BatchRslts.Batch.WaterMeters[i].Compound()) { /// Else if this is a compound meter for (byte b = (byte)CompoundMeterId.CompoundMain; b <= (byte)CompoundMeterId.Compound; b++) { Results.Entities.MeterTestRslt mtrRslt = ProcessData.BatchRslts.GetMeterTestRslt(tstRslt.Name(), i, (CompoundMeterId)b); if (mtrRslt != null) { sb.Append(";"); switch ((CompoundMeterId)b) { case CompoundMeterId.CompoundMain: sb.Append(ProcessData.BatchRslts.Batch.WaterMeters[i].SerialNr); /// CE break; case CompoundMeterId.CompoundAux: sb.Append(ProcessData.BatchRslts.Batch.WaterMeters[i].SerialNrAux); /// CE break; case CompoundMeterId.Compound: sb.Append(ProcessData.BatchRslts.Batch.WaterMeters[i].SerialNr); /// CE break; } sb.Append(";"); sb.Append(mtrRslt.VolumeStart); /// CF WM Vinit - pri pevnom starte pociatocny stav natukany alebo cez inteligentny system sb.Append(";"); sb.Append(mtrRslt.VolumeEnd); /// CG WM Vfin - pri pevnom starte konecny stav natukany alebo cez inteligentny system sb.Append(";"); sb.Append(mtrRslt.VolumeMeter); /// CH WM Vmer - objem namerany vodomerom sb.Append(";"); sb.Append(mtrRslt.VolumeRef); /// CI WM Vet - objem namerany stanicou sb.Append(";"); sb.Append(mtrRslt.Error); /// CJ WM Emt - chyba vodomerom nameraneho objemu sb.Append(";"); sb.Append(" "); /// CK WM U - neistota (zatial nechat prazdne) sb.Append(";"); sb.Append(mtrRslt.PulsesMeter); /// CL WM Np met - pocet impulzov zo skusaneho meradla sb.Append(";"); sb.Append(mtrRslt.PulsesMaster); /// CM WM Np elm - pocet impulzov etalonu pocas merania pre prislusny vodomer sb.Append(";"); sb.Append(mtrRslt.TestTime); /// CN WM Tmet - cas merania (obmedzany pri synchro skuske) sb.Append(";"); sb.Append(mtrRslt.Passed ? "OK" : "NOK"); /// CO WM Vysledok (t.j. ci je v hraniciach chyb) - OK/NOK sb.Append(";"); sb.Append(" "); /// CP WM AN value - hodnota z analogoveho prevodnika (teraz nic) bool isCamera = mtrRslt.IsCamera(); sb.Append(";"); sb.Append(isCamera ? mtrRslt.VolumeStart * mtrRslt.PulsesPerLiter : 0); /// CQ WM Phi_start - pri hodnotach z kamery sb.Append(";"); sb.Append(isCamera ? mtrRslt.VolumeEnd * mtrRslt.PulsesPerLiter : 0); /// CR WM Phi_end - ' ' - sb.Append(";"); sb.Append(isCamera ? mtrRslt.TimestampStart : 0); /// CS WM Time_start - ' ' - sb.Append(";"); sb.Append(isCamera ? mtrRslt.TimestampEnd : 0); /// CT WM Time_end - ' ' - sb.Append(";"); sb.Append(isCamera ? mtrRslt.PulsesPerLiter : 0); /// CU WM Degree per liter sb.Append(";"); sb.Append(0); /// CV Analog out 1 (max mA) sb.Append(";"); sb.Append(0); /// CW Analog out 2 (V) sb.Append(";"); sb.Append(0); /// CX Analog out 3 (min mA) sb.Append(";"); sb.Append(0); /// CY Analog out 4 (max Q) } } } else /// if (ProcessData.BatchRslts.WaterMeters[i].HeatMeter()) { /// Else this is a heat meter Results.Entities.MeterTestRslt volumeMtr = ProcessData.BatchRslts.GetMeterTestRslt(tstRslt.Name(), i, CompoundMeterId.HeatMeterVolume); Results.Entities.MeterTestRslt energyMtr = ProcessData.BatchRslts.GetMeterTestRslt(tstRslt.Name(), i, CompoundMeterId.HeatMeterEnergy); if (volumeMtr != null) { sb.Append(";"); sb.Append(ProcessData.BatchRslts.Batch.WaterMeters[i].SerialNr); /// WM Ser.No. sb.Append(";"); sb.Append(volumeMtr.VolumeStart); /// WM Vstart - pociatocny stav pri pevnom starte alebo zachyteny pri data streame sb.Append(";"); sb.Append(volumeMtr.VolumeEnd); /// WM Vend - konecny stav pri pevnom starte alebo zachyteny pri data streame sb.Append(";"); sb.Append(volumeMtr.VolumeMeter); /// WM Vmer - objem namerany vodomerom sb.Append(";"); sb.Append(volumeMtr.VolumeRef); /// WM Vref - objem namerany stanicou sb.Append(";"); sb.Append(volumeMtr.Error); /// WM Emt - chyba vodomerom nameraneho objemu #if IPERL sb.Append(";"); sb.Append(ProcessData.BatchRslts.Batch.WaterMeters[i].CalibFactor); /// iPerl calibration factor used during the test / ... #else sb.Append(";"); sb.Append(" "); /// nechat prazdne #endif sb.Append(";"); sb.Append(volumeMtr.PulsesMeter); /// WM Np met - pocet impulzov zo skusaneho meradla sb.Append(";"); sb.Append(volumeMtr.PulsesMaster); /// WM Np elm - pocet impulzov etalonu pocas merania pre prislusny vodomer sb.Append(";"); sb.Append(volumeMtr.TestTime); /// WM Tmet - cas merania (obmedzany pri synchro skuske) sb.Append(";"); sb.Append(volumeMtr.Passed ? "OK" : "NOK"); /// WM Vysledok (t.j. ci je v hraniciach chyb) - OK/NOK #if IPERL sb.Append(";"); sb.Append(volumeMtr.WaterMeter.Q2CorrRL); /// iPerl Q2 correction factor used during the test / AN value - hodnota z analogoveho prevodnika #else sb.Append(";"); sb.Append(" "); /// nechat prazdne #endif sb.Append(";"); sb.Append(volumeMtr.VolumeStart); /// WM Volume_start - pri datastreamovych hodnotach (alebo kamera) sb.Append(";"); sb.Append(volumeMtr.TimestampStart); /// WM Time_start - ' ' - sb.Append(";"); sb.Append(volumeMtr.VolumeEnd); /// WM Volume_end - ' ' - sb.Append(";"); sb.Append(volumeMtr.TimestampEnd); /// WM Time_end - ' ' - } if (energyMtr != null) { sb.Append(";"); sb.Append(ProcessData.BatchRslts.Batch.WaterMeters[i].SerialNr); /// WM Ser.No. sb.Append(";"); sb.Append(energyMtr.VolumeStart); /// WM Vstart - pociatocny stav pri pevnom starte alebo zachyteny pri data streame sb.Append(";"); sb.Append(energyMtr.VolumeEnd); /// WM Vend - konecny stav pri pevnom starte alebo zachyteny pri data streame sb.Append(";"); sb.Append(energyMtr.VolumeMeter); /// WM Vmer - objem namerany vodomerom sb.Append(";"); sb.Append(energyMtr.VolumeRef); /// WM Vref - objem namerany stanicou sb.Append(";"); sb.Append(energyMtr.Error); /// WM Emt - chyba vodomerom nameraneho objemu #if IPERL sb.Append(";"); sb.Append(ProcessData.BatchRslts.Batch.WaterMeters[i].CalibFactor); /// iPerl calibration factor used during the test / ... #else sb.Append(";"); sb.Append(" "); /// nechat prazdne #endif sb.Append(";"); sb.Append(energyMtr.PulsesMeter); /// WM Np met - pocet impulzov zo skusaneho meradla sb.Append(";"); sb.Append(energyMtr.PulsesMaster); /// WM Np elm - pocet impulzov etalonu pocas merania pre prislusny vodomer sb.Append(";"); sb.Append(energyMtr.TestTime); /// WM Tmet - cas merania (obmedzany pri synchro skuske) sb.Append(";"); sb.Append(energyMtr.Passed ? "OK" : "NOK"); /// WM Vysledok (t.j. ci je v hraniciach chyb) - OK/NOK #if IPERL sb.Append(";"); sb.Append(energyMtr.WaterMeter.Q2CorrRL); /// iPerl Q2 correction factor used during the test / AN value - hodnota z analogoveho prevodnika #else sb.Append(";"); sb.Append(" "); /// nechat prazdne #endif sb.Append(";"); sb.Append(energyMtr.VolumeStart); /// WM Volume_start - pri datastreamovych hodnotach (alebo kamera) sb.Append(";"); sb.Append(energyMtr.TimestampStart); /// WM Time_start - ' ' - sb.Append(";"); sb.Append(energyMtr.VolumeEnd); /// WM Volume_end - ' ' - sb.Append(";"); sb.Append(energyMtr.TimestampEnd); /// WM Time_end - ' ' - } } } } sb.Append(";"); } catch (Exception exc) { log.ErrorFormat("Preparinging SummaryResults B{0}/{1} failed: {2}", tstRslt.Batch.BatchNr, tstRslt.Name(), exc.Message); } return sb.ToString(); } /// /// Create a simulated test result (single meter). /// /// Test to be simulated /// Test result protected void MakeSimulated(Config.Entities.Test test, int repetitionNr, int part, float errorPctBase) { string fullTestName = Results.Utils.GetTestName(test.Name, test.Repeats, repetitionNr); Results.Entities.TestRslt tstRslt = ProcessData.BatchRslts.GetTestRslt(fullTestName, part); Results.Utils.GetCounterStates(tstRslt, Program.LocalSettings.Counters); if (tstRslt == null) return; /// Prevent program crash in certain cases tstRslt.AmbTempMean = 20.0f; tstRslt.AmbPressMean = 1.0f; tstRslt.AmbHumiMean = 50.0f; tstRslt.PressUpStart = 1.0f; tstRslt.PressDownStart = 1.0f; tstRslt.TempUpStart = 20.0f; tstRslt.TempDownStart = 20.0f; tstRslt.TempDivStart = 20.0f; tstRslt.PressUpEnd = 1.0f; tstRslt.PressDownEnd = 1.0f; tstRslt.TempUpEnd = 20.0f; tstRslt.TempDownEnd = 20.0f; tstRslt.TempDivEnd = 20.0f; tstRslt.PressUpMean = 1.0f; tstRslt.PressDownMean = 1.0f; tstRslt.TempUpMean = 20.0f; tstRslt.TempDownMean = 20.0f; tstRslt.TempDivMean = 20.0f; tstRslt.PressUpMin = 1.0f; tstRslt.PressDownMin = 1.0f; tstRslt.TempUpMin = 20.0f; tstRslt.TempDownMin = 20.0f; tstRslt.TempDivMin = 20.0f; tstRslt.PressUpMax = 1.0f; tstRslt.PressDownMax = 1.0f; tstRslt.TempUpMax = 20.0f; tstRslt.TempDownMax = 20.0f; tstRslt.TempDivMax = 20.0f; tstRslt.ConductMin = Conductivity.Val; tstRslt.ConductMax = Conductivity.Val; tstRslt.DensityIn = Config.Formulas.RealDensity(); tstRslt.DensityLine = Config.Formulas.RealDensity(); tstRslt.DensityDiv = Config.Formulas.RealDensity(); tstRslt.MethodClass = TbfComponents.FindComponent(test.Method).ClassName; tstRslt.StartTime = DateTime.Now; tstRslt.EndTime = DateTime.Now + new TimeSpan(0,0,1); tstRslt.FlowSetTime = 10; tstRslt.TestTime = tstRslt.TargetTime(); tstRslt.PulsesMaster = (outPath.FlowMeter.LtrPerPulse > 1E-6) ? (1.0075 * tstRslt.TargetVolume() / outPath.FlowMeter.LtrPerPulse) : 1; tstRslt.MassStartRaw = 0; tstRslt.MassStart = Config.Formulas.CorrectedValue(tstRslt.MassStartRaw, outPath.Scale.Corrections); tstRslt.MassEndRaw = tstRslt.TargetVolume() * Config.Formulas.RealDensity() / 1000.0f; tstRslt.MassEnd = Config.Formulas.CorrectedValue(tstRslt.MassEndRaw, outPath.Scale.Corrections); tstRslt.FlowMass = 3600.0 * (tstRslt.MassEnd - tstRslt.MassStart) / tstRslt.TestTime; tstRslt.FlowVolume = 3.6 * outPath.FlowMeter.LtrPerPulse * tstRslt.PulsesMaster / tstRslt.TestTime; tstRslt.Buoyancy = Formulas.Buoyancy(); tstRslt.VolumeCTV = 1000 * tstRslt.Buoyancy * (tstRslt.MassEnd - tstRslt.MassStart) / tstRslt.DensityLine; /// [l] commercially true volume tstRslt.VolumeMaster = outPath.FlowMeter.LtrPerPulse * tstRslt.PulsesMaster; /// [l] volume from the master flow meter tstRslt.ConstMasterRaw = outPath.FlowMeter.LtrPerPulse; /// Uncorrected master flowmeter coefficient tstRslt.ConstMasterCorr = outPath.FlowMeter.LtrPerPulseCorrected(tstRslt.FlowVolume, 0); /// Corrected master pulses per liter tstRslt.ConstMaster = (tstRslt.VolumeMaster == 0) ? tstRslt.ConstMasterCorr : (outPath.FlowMeter.LtrPerPulse * tstRslt.VolumeCTV / tstRslt.VolumeMaster); tstRslt.ErrorMaster = Config.Formulas.ErrorFromVolumes(tstRslt.VolumeMaster, tstRslt.VolumeCTV); tstRslt.FlowMean = (float)RefFlowStat.Average; tstRslt.FlowStart = (float)RefFlowStat.First; tstRslt.FlowEnd = (float)RefFlowStat.Last; tstRslt.FlowMin = (float)RefFlowStat.Min; tstRslt.FlowMax = (float)RefFlowStat.Max; for (int i = 0; i < BatchRslts.WMPositionsCount; i++) { float errorPct = errorPctBase + 0.05f * i; Results.Entities.MeterTestRslt meterRslt = ProcessData.BatchRslts.GetMeterTestRslt(fullTestName, i, CompoundMeterId.Single); IRegReader regReader = sensPath.RegisterReaders[i]; if (meterRslt != null && regReader != null) { meterRslt.VolumeMeter = tstRslt.TargetVolume() * (1.0 + 0.01 * errorPct); meterRslt.PulsesMeter = regReader.PulsesPerLtr * meterRslt.VolumeMeter; meterRslt.PulsesMaster = tstRslt.PulsesMaster; meterRslt.PulsesPerLiter = regReader.PulsesPerLtr; meterRslt.VolumeStart = 0; meterRslt.VolumeEnd = meterRslt.VolumeMeter; meterRslt.VolumeRef = tstRslt.TargetVolume(); meterRslt.TimestampStart = 0; meterRslt.TimestampEnd = tstRslt.TargetTime(); meterRslt.TestTime = tstRslt.TargetTime(); meterRslt.Error = errorPct; meterRslt.Passed = (errorPct >= tstRslt.ErrLimLo() + tstRslt.ErrLimMargin()) && (errorPct <= tstRslt.ErrLimHi() - tstRslt.ErrLimMargin()); meterRslt.TestDone = true; tstRslt.TestDone = true; } } tstRslt.Components = Results.Entities.Components .UpdateList(BatchRslts.ComponentsList, new Results.Entities.Components((BenchInfo != null) ? BenchInfo.TestBenchId : 1, (BenchInfo != null) ? BenchInfo.TestBenchName : "testbench", inPath.Pump != null ? inPath.Pump.Name : string.Empty, outPath.FlowMeter != null ? outPath.FlowMeter.Name : string.Empty, outPath.Scale != null ? outPath.Scale.Name : string.Empty, outPath.RegulValve != null ? outPath.RegulValve.Name : string.Empty, outPath.Diverter != null ? outPath.Diverter.Name : string.Empty)); } /// /// Create a simulated test result (compound meter). /// /// Test to be simulated /// Test result protected void MakeSimulatedCompound(Config.Entities.Test test, int repetitionNr, int part, float errorPct, float mainPart) { string fullTestName = Results.Utils.GetTestName(test.Name, test.Repeats, repetitionNr); Results.Entities.TestRslt tstRslt = ProcessData.BatchRslts.GetTestRslt(fullTestName, part); if (tstRslt != null) { tstRslt.MethodClass = TbfComponents.FindComponent(test.Method).ClassName; tstRslt.StartTime = DateTime.Now; tstRslt.EndTime = DateTime.Now + new TimeSpan(0, 0, 1); tstRslt.FlowSetTime = 10; tstRslt.TestTime = tstRslt.TargetTime(); /// TODO: Verify whether 'ltrPerRefPulse' is up to date tstRslt.PulsesMaster = (LtrPerRefPulse > 1E-6) ? (tstRslt.TargetVolume() / LtrPerRefPulse) : 1; tstRslt.ConstMasterRaw = LtrPerRefPulse; tstRslt.ConstMaster = LtrPerRefPulse; tstRslt.MassStartRaw = 0; tstRslt.MassStart = 0; tstRslt.MassEndRaw = tstRslt.TargetVolume() * Config.Formulas.RealDensity() / 1000.0f; tstRslt.MassEnd = tstRslt.MassEndRaw; tstRslt.DensityIn = Config.Formulas.RealDensity(); tstRslt.DensityLine = Config.Formulas.RealDensity(); tstRslt.DensityDiv = Config.Formulas.RealDensity(); tstRslt.Buoyancy = Formulas.Buoyancy(); tstRslt.FlowMass = tstRslt.MassEnd / tstRslt.TargetTime(); tstRslt.FlowVolume = tstRslt.TargetVolume() / tstRslt.TargetTime(); tstRslt.VolumeCTV = tstRslt.TargetVolume(); tstRslt.VolumeMaster = tstRslt.TargetVolume(); tstRslt.ErrorMaster = 0; tstRslt.AmbTempMean = 20.0f; tstRslt.AmbPressMean = 1.0f; tstRslt.AmbHumiMean = 50.0f; tstRslt.PressUpStart = 1.0f; tstRslt.PressDownStart = 1.0f; tstRslt.TempUpStart = 20.0f; tstRslt.TempDownStart = 20.0f; tstRslt.TempDivStart = 20.0f; tstRslt.PressUpEnd = 1.0f; tstRslt.PressDownEnd = 1.0f; tstRslt.TempUpEnd = 20.0f; tstRslt.TempDownEnd = 20.0f; tstRslt.TempDivEnd = 20.0f; tstRslt.PressUpMean = 1.0f; tstRslt.PressDownMean = 1.0f; tstRslt.TempUpMean = 20.0f; tstRslt.TempDownMean = 20.0f; tstRslt.TempDivMean = 20.0f; tstRslt.PressUpMin = 1.0f; tstRslt.PressDownMin = 1.0f; tstRslt.TempUpMin = 20.0f; tstRslt.TempDownMin = 20.0f; tstRslt.TempDivMin = 20.0f; tstRslt.PressUpMax = 1.0f; tstRslt.PressDownMax = 1.0f; tstRslt.TempUpMax = 20.0f; tstRslt.TempDownMax = 20.0f; tstRslt.TempDivMax = 20.0f; tstRslt.ConductMin = Conductivity.Val; tstRslt.ConductMax = Conductivity.Val; tstRslt.FlowMean = (float)RefFlowStat.Average; tstRslt.FlowStart = (float)RefFlowStat.First; tstRslt.FlowEnd = (float)RefFlowStat.Last; tstRslt.FlowMin = (float)RefFlowStat.Min; tstRslt.FlowMax = (float)RefFlowStat.Max; for (int i = 0; i < BatchRslts.WMPositionsCount; i++) { Results.Entities.MeterTestRslt compoundRslt = ProcessData.BatchRslts.GetMeterTestRslt(fullTestName, i, CompoundMeterId.Compound); Results.Entities.MeterTestRslt mainRslt = ProcessData.BatchRslts.GetMeterTestRslt(fullTestName, i, CompoundMeterId.CompoundMain); Results.Entities.MeterTestRslt auxRslt = ProcessData.BatchRslts.GetMeterTestRslt(fullTestName, i, CompoundMeterId.CompoundAux); double compoundVolume = tstRslt.TargetVolume() * (1.0 + 0.01 * errorPct); double mainVolume = compoundVolume * mainPart; double auxVolume = compoundVolume * (1.0 - mainPart); for (int isAux = 0; isAux <= 1; isAux++) /// 0=main, 1=aux { GenericDevices.IRegReader regReader = sensPath.RegisterReaders[2 * i + isAux]; Results.Entities.MeterTestRslt meterRslt = (isAux == 0) ? mainRslt : auxRslt; if (meterRslt != null && regReader != null) { meterRslt.VolumeMeter = (isAux == 0) ? mainVolume : auxVolume; meterRslt.PulsesMeter = regReader.PulsesPerLtr * meterRslt.VolumeMeter; meterRslt.PulsesMaster = tstRslt.PulsesMaster; meterRslt.PulsesPerLiter = regReader.PulsesPerLtr; meterRslt.VolumeStart = 0; meterRslt.VolumeEnd = meterRslt.VolumeMeter; meterRslt.VolumeRef = tstRslt.TargetVolume(); meterRslt.TimestampStart = 0; meterRslt.TimestampEnd = tstRslt.TargetTime(); meterRslt.TestTime = tstRslt.TargetTime(); meterRslt.Error = Formulas.ErrorFromVolumes(meterRslt.VolumeMeter, tstRslt.VolumeCTV); meterRslt.Passed = (errorPct >= tstRslt.ErrLimLo() + tstRslt.ErrLimMargin()) && (errorPct <= tstRslt.ErrLimHi() - tstRslt.ErrLimMargin()); meterRslt.TestDone = true; } } compoundRslt.VolumeRef = tstRslt.VolumeCTV; /// [l] must be calculated before main & aux. meter error compoundRslt.VolumeMeter = mainRslt.VolumeMeter + auxRslt.VolumeMeter; compoundRslt.PulsesMaster = tstRslt.PulsesMaster; compoundRslt.TestTime = tstRslt.TargetTime(); compoundRslt.Error = Formulas.ErrorFromVolumes(compoundRslt.VolumeMeter, tstRslt.VolumeCTV); compoundRslt.Passed = (compoundRslt.Error >= tstRslt.ErrLimLo() + tstRslt.ErrLimMargin()) && (compoundRslt.Error <= tstRslt.ErrLimHi() - tstRslt.ErrLimMargin()); compoundRslt.TestDone = true; tstRslt.TestDone = true; } tstRslt.Components = Results.Entities.Components.UpdateList(BatchRslts.ComponentsList, new Results.Entities.Components((BenchInfo != null) ? BenchInfo.TestBenchId : 1, (BenchInfo != null) ? BenchInfo.TestBenchName : "testbench", inPath.Pump != null ? inPath.Pump.Name : string.Empty, outPath.FlowMeter != null ? outPath.FlowMeter.Name : string.Empty, outPath.Scale != null ? outPath.Scale.Name : string.Empty, outPath.RegulValve != null ? outPath.RegulValve.Name : string.Empty, outPath.Diverter != null ? outPath.Diverter.Name : string.Empty)); } } /// /// Create a simulated test result (heat meters). /// /// Test to be simulated /// Test result protected void MakeSimulatedHeatMeters(Config.Entities.Test test, int repetitionNr, int part, float errorPct, double energy, float energyErrLimLo, float energyErrLimHi, bool evaluateVolume) { string fullTestName = Common.Utils.GetTestName(test.Name, test.Repeats, repetitionNr); Results.Entities.TestRslt tstRslt = ProcessData.BatchRslts.GetTestRslt(fullTestName, part); tstRslt.MethodClass = TbfComponents.FindComponent(test.Method).ClassName; tstRslt.StartTime = DateTime.Now; tstRslt.EndTime = DateTime.Now + new TimeSpan(0, 0, 1); tstRslt.FlowSetTime = 10; tstRslt.TestTime = tstRslt.TargetTime(); /// TODO: Verify whether 'ltrPerRefPulse' is up to date tstRslt.PulsesMaster = (LtrPerRefPulse > 1E-6) ? (tstRslt.TargetVolume() / LtrPerRefPulse) : 1; tstRslt.ConstMasterRaw = LtrPerRefPulse; tstRslt.ConstMaster = LtrPerRefPulse; tstRslt.MassStartRaw = 0; tstRslt.MassStart = 0; tstRslt.MassEndRaw = tstRslt.TargetVolume() * Config.Formulas.RealDensity() / 1000.0f; tstRslt.MassEnd = tstRslt.MassEndRaw; tstRslt.DensityIn = Config.Formulas.RealDensity(); tstRslt.DensityLine = Config.Formulas.RealDensity(); tstRslt.DensityDiv = Config.Formulas.RealDensity(); tstRslt.Buoyancy = Formulas.Buoyancy(); tstRslt.FlowMass = tstRslt.MassEnd / tstRslt.TargetTime(); tstRslt.FlowVolume = tstRslt.TargetVolume() / tstRslt.TargetTime(); tstRslt.VolumeCTV = tstRslt.TargetVolume(); tstRslt.VolumeMaster = tstRslt.TargetVolume(); tstRslt.ErrorMaster = 0; tstRslt.AmbTempMean = 20.0f; tstRslt.AmbPressMean = 1.0f; tstRslt.AmbHumiMean = 50.0f; tstRslt.PressUpStart = 1.0f; tstRslt.PressDownStart = 1.0f; tstRslt.TempUpStart = 20.0f; tstRslt.TempDownStart = 20.0f; tstRslt.TempDivStart = 20.0f; tstRslt.PressUpEnd = 1.0f; tstRslt.PressDownEnd = 1.0f; tstRslt.TempUpEnd = 20.0f; tstRslt.TempDownEnd = 20.0f; tstRslt.TempDivEnd = 20.0f; tstRslt.PressUpMean = 1.0f; tstRslt.PressDownMean = 1.0f; tstRslt.TempUpMean = 20.0f; tstRslt.TempDownMean = 20.0f; tstRslt.TempDivMean = 20.0f; tstRslt.PressUpMin = 1.0f; tstRslt.PressDownMin = 1.0f; tstRslt.TempUpMin = 20.0f; tstRslt.TempDownMin = 20.0f; tstRslt.TempDivMin = 20.0f; tstRslt.PressUpMax = 1.0f; tstRslt.PressDownMax = 1.0f; tstRslt.TempUpMax = 20.0f; tstRslt.TempDownMax = 20.0f; tstRslt.TempDivMax = 20.0f; tstRslt.ConductMin = Conductivity.Val; tstRslt.ConductMax = Conductivity.Val; tstRslt.FlowMean = 0; /// TODO tstRslt.FlowMax = 0; /// TODO for (int i = 0; i < BatchRslts.WMPositionsCount; i++) { Results.Entities.MeterTestRslt energyRslt = ProcessData.BatchRslts.GetMeterTestRslt(fullTestName, i, CompoundMeterId.HeatMeterEnergy); Results.Entities.MeterTestRslt volumeRslt = ProcessData.BatchRslts.GetMeterTestRslt(fullTestName, i, CompoundMeterId.HeatMeterVolume); GenericDevices.IRegReader volumeRegReader = (sensPath.RegisterReaders.Length > 2 * i) ? sensPath.RegisterReaders[2 * i] : null; GenericDevices.IRegReader energyRegReader = (sensPath.RegisterReaders.Length > 2 * i + 1) ? sensPath.RegisterReaders[2 * i + 1] : null; double volumeMeter = tstRslt.TargetVolume() * (1.0 + 0.01 * errorPct); double energyMeter = energy * (1.0 + 0.01 * errorPct); if (volumeRslt != null && volumeRegReader != null) { volumeRslt.VolumeMeter = volumeMeter; volumeRslt.PulsesMeter = volumeRegReader.PulsesPerLtr * volumeMeter; volumeRslt.PulsesMaster = tstRslt.PulsesMaster; volumeRslt.PulsesPerLiter = volumeRegReader.PulsesPerLtr; volumeRslt.VolumeStart = 0; volumeRslt.VolumeEnd = volumeMeter; volumeRslt.VolumeRef = tstRslt.TargetVolume(); volumeRslt.TimestampStart = 0; volumeRslt.TimestampEnd = tstRslt.TargetTime(); volumeRslt.TestTime = tstRslt.TargetTime(); volumeRslt.Error = Formulas.ErrorFromVolumes(volumeMeter, tstRslt.VolumeCTV); volumeRslt.Passed = !evaluateVolume || ((errorPct >= tstRslt.ErrLimLo() + tstRslt.ErrLimMargin()) && (errorPct <= tstRslt.ErrLimHi() - tstRslt.ErrLimMargin())); volumeRslt.TestDone = true; tstRslt.TestDone = true; } if (energyRslt != null && energyRegReader != null) { energyRslt.VolumeMeter = energyMeter; energyRslt.PulsesMeter = energyRegReader.PulsesPerLtr * energyMeter; energyRslt.PulsesMaster = tstRslt.PulsesMaster; energyRslt.PulsesPerLiter = energyRegReader.PulsesPerLtr; energyRslt.VolumeStart = 0; energyRslt.VolumeEnd = energyMeter; energyRslt.VolumeRef = energy; energyRslt.TimestampStart = 0; energyRslt.TimestampEnd = tstRslt.TargetTime(); energyRslt.TestTime = tstRslt.TargetTime(); energyRslt.Error = Formulas.ErrorFromVolumes(energyMeter, energy); energyRslt.Passed = (errorPct >= energyErrLimLo) && (errorPct <= energyErrLimHi); energyRslt.TestDone = true; tstRslt.TestDone = true; } } tstRslt.Components = Results.Entities.Components .UpdateList(BatchRslts.ComponentsList, new Results.Entities.Components((BenchInfo != null) ? BenchInfo.TestBenchId : 1, (BenchInfo != null) ? BenchInfo.TestBenchName : "testbench", inPath.Pump != null ? inPath.Pump.Name : string.Empty, outPath.FlowMeter != null ? outPath.FlowMeter.Name : string.Empty, outPath.Scale != null ? outPath.Scale.Name : string.Empty, outPath.RegulValve != null ? outPath.RegulValve.Name : string.Empty, outPath.Diverter != null ? outPath.Diverter.Name : string.Empty)); } protected bool TestAndLogUiCmdStop(IList e) { return TestAndLogUiCmdStop(null, e); } /// /// Returns true and makes a log when 'e' contains Event.UiCmdStop /// /// test or null (only for logs) /// /// protected bool TestAndLogUiCmdStop(Test test, IList e) { if (!e.Contains(Event.UiCmdStop)) return false; log.FatalFormat("STOP pressed: Procedure={0}, Test={1}, State={2}", (StateMachine.Procedure == null) ? "?" : StateMachine.Procedure.Name, (test == null) ? "?" : test.Name, State.CurrentState.Name); if (test != null) { log.FatalFormat("Process values:"); log.FatalFormat(" Method: {0}", test.Method); log.FatalFormat(" Test start time: {0}", TestStartTime.ToShortTimeString()); log.FatalFormat(" Feeding path: {0}", (inPath != null) ? inPath.ToString() : "none"); log.FatalFormat(" Bench path: {0}", (benchPath != null) ? benchPath.ToString() : "none"); log.FatalFormat(" Output path: {0}", (outPath != null) ? outPath.ToString() : "none"); if (inPath.Pump is IPump) log.FatalFormat(" Pump power: {0}%", (inPath.Pump as IPump).Power); else if (inPath.Pump is IValve) log.FatalFormat(" Feeding valve: {0}", (inPath.Pump as IValve).State ? "open" : "close"); if (outPath.RegulValve is IRegulValve) log.FatalFormat(" Regulation valve position: {0}%", outPath.RegulValve.Position); log.FatalFormat(" Flow: {0}", RefFlow); log.FatalFormat(" Mass: {0}", Mass); log.FatalFormat(" Start mass: {0}", StartMass); log.FatalFormat(" Liter/ref.pulse: {0}", LtrPerRefPulse); log.FatalFormat(" Reference pulses: {0}", RefPulses); } return true; } } }