예제 #1
0
        ///<summary>Get the shortest time step to activate the control.</summary>
        private long GetRequiredTimeStep(EpanetNetwork net, long htime, long tstep)
        {
            long t = 0;

            // Node control
            if (Node != null)
            {
                if (!(Node is SimulationTank)) // Check if node is a tank
                {
                    return(tstep);
                }

                double h = _node.SimHead;   // Current tank grade
                double q = _node.SimDemand; // Flow into tank

                if (Math.Abs(q) <= Constants.QZERO)
                {
                    return(tstep);
                }

                if ((h < Grade && Type == ControlType.HILEVEL && q > 0.0) || // Tank below hi level & filling
                    (h > Grade && Type == ControlType.LOWLEVEL && q < 0.0))
                // Tank above low level & emptying
                {
                    SimulationTank tank = (SimulationTank)Node;
                    double         v    = tank.FindVolume(net.FieldsMap, Grade) - tank.SimVolume;
                    t = (long)Math.Round(v / q); // Time to reach level
                }
            }

            // Time control
            if (Type == ControlType.TIMER)
            {
                if (Time > htime)
                {
                    t = Time - htime;
                }
            }

            // Time-of-day control
            if (Type == ControlType.TIMEOFDAY)
            {
                long t1 = (htime + net.Tstart) % Constants.SECperDAY;
                long t2 = Time;
                if (t2 >= t1)
                {
                    t = t2 - t1;
                }
                else
                {
                    t = Constants.SECperDAY - t1 + t2;
                }
            }

            // Revise time step
            if (t > 0 && t < tstep)
            {
                SimulationLink link = Link;

                // Check if rule actually changes link status or setting
                if (link != null &&
                    (link.Type > LinkType.PIPE && link.SimSetting != Setting) ||
                    (link.SimStatus != Status))
                {
                    tstep = t;
                }
            }

            return(tstep);
        }
예제 #2
0
        /// <summary>Implements simple controls based on time or tank levels.</summary>
        public static int StepActions(
            TraceSource log,
            EpanetNetwork net,
            IEnumerable <SimulationControl> controls,
            long htime)
        {
            int setsum = 0;

            // Examine each control statement
            foreach (SimulationControl control  in  controls)
            {
                bool reset = false;

                // Make sure that link is defined
                if (control.Link == null)
                {
                    continue;
                }

                // Link is controlled by tank level
                var node = control.Node as SimulationTank;
                if (node != null)
                {
                    double h     = node.SimHead;
                    double vplus = Math.Abs(node.SimDemand);

                    SimulationTank tank = node;

                    double v1 = tank.FindVolume(net.FieldsMap, h);
                    double v2 = tank.FindVolume(net.FieldsMap, control.Grade);

                    if (control.Type == ControlType.LOWLEVEL && v1 <= v2 + vplus)
                    {
                        reset = true;
                    }
                    if (control.Type == ControlType.HILEVEL && v1 >= v2 - vplus)
                    {
                        reset = true;
                    }
                }

                // Link is time-controlled
                if (control.Type == ControlType.TIMER)
                {
                    if (control.Time == htime)
                    {
                        reset = true;
                    }
                }

                //  Link is time-of-day controlled
                if (control.Type == ControlType.TIMEOFDAY)
                {
                    if ((htime + net.Tstart) % Constants.SECperDAY == control.Time)
                    {
                        reset = true;
                    }
                }

                // Update link status & pump speed or valve setting
                if (reset)
                {
                    StatType       s1, s2;
                    SimulationLink link = control.Link;

                    if (link.SimStatus <= StatType.CLOSED)
                    {
                        s1 = StatType.CLOSED;
                    }
                    else
                    {
                        s1 = StatType.OPEN;
                    }

                    s2 = control.Status;

                    double k1 = link.SimSetting;
                    double k2 = k1;

                    if (control.Link.Type > LinkType.PIPE)
                    {
                        k2 = control.Setting;
                    }

                    if (s1 != s2 || k1 != k2)
                    {
                        link.SimStatus  = s2;
                        link.SimSetting = k2;
                        if (net.StatFlag != StatFlag.NO)
                        {
                            LogControlAction(log, control, htime);
                        }
                        setsum++;
                    }
                }
            }

            return(setsum);
        }
예제 #3
0
        /// <summary>
        /// Updates next time step by checking if any rules will fire before then;
        /// also updates tank levels.
        /// </summary>
        public static void MinimumTimeStep(
            EpanetNetwork net,
            TraceSource log,
            SimulationRule[] rules,
            List <SimulationTank> tanks,
            long htime,
            long tstep,
            double dsystem,
            out long tstepOut,
            out long htimeOut)
        {
            long dt;  // Normal time increment for rule evaluation
            long dt1; // Actual time increment for rule evaluation

            // Find interval of time for rule evaluation
            long tnow = htime;        // Start of time interval for rule evaluation
            long tmax = tnow + tstep; // End of time interval for rule evaluation

            //If no rules, then time increment equals current time step
            if (rules.Length == 0)
            {
                dt  = tstep;
                dt1 = dt;
            }
            else
            {
                // Otherwise, time increment equals rule evaluation time step and
                // first actual increment equals time until next even multiple of
                // Rulestep occurs.
                dt  = net.RuleStep;
                dt1 = net.RuleStep - tnow % net.RuleStep;
            }

            // Make sure time increment is no larger than current time step
            dt  = Math.Min(dt, tstep);
            dt1 = Math.Min(dt1, tstep);

            if (dt1 == 0)
            {
                dt1 = dt;
            }

            // Step through time, updating tank levels, until either
            // a rule fires or we reach the end of evaluation period.
            //
            // Note: we are updating the global simulation time (Htime)
            //       here because it is used by functions in RULES.C(this class)
            //       to evaluate rules when checkrules() is called.
            //       It is restored to its original value after the
            //       rule evaluation process is completed (see below).
            //       Also note that dt1 will equal dt after the first
            //       time increment is taken.

            do
            {
                htime += dt1;                                              // Update simulation clock
                SimulationTank.StepWaterLevels(tanks, net.FieldsMap, dt1); // Find new tank levels
                if (Check(net, rules, log, htime, dt1, dsystem) != 0)
                {
                    break;                        // Stop if rules fire
                }
                dt  = Math.Min(dt, tmax - htime); // Update time increment
                dt1 = dt;                         // Update actual increment
            }while (dt > 0);

            //Compute an updated simulation time step (*tstep)
            // and return simulation time to its original value
            tstepOut = htime - tnow;
            htimeOut = tnow;
        }
예제 #4
0
        /// <summary>Closes link flowing into full or out of empty tank.</summary>
        private void TankStatus(EpanetNetwork net)
        {
            double         q  = flow;
            SimulationNode n1 = First;
            SimulationNode n2 = Second;

            // Make node n1 be the tank
            if (!(n1 is SimulationTank))
            {
                if (!(n2 is SimulationTank))
                {
                    return; // neither n1 or n2 is a tank
                }
                // N2 is a tank, swap !
                SimulationNode n = n1;
                n1 = n2;
                n2 = n;
                q  = -q;
            }

            double h = n1.SimHead - n2.SimHead;

            SimulationTank tank = (SimulationTank)n1;

            // Skip reservoirs & closed links
            if (tank.Area == 0.0 || status <= StatType.CLOSED)
            {
                return;
            }

            // If tank full, then prevent flow into it
            if (tank.SimHead >= tank.Hmax - net.HTol)
            {
                //Case 1: Link is a pump discharging into tank
                if (Type == LinkType.PUMP)
                {
                    if (Second == n1)
                    {
                        status = StatType.TEMPCLOSED;
                    }
                }
                else if (CvStatus(net, StatType.OPEN, h, q) == StatType.CLOSED)
                {
                    //  Case 2: Downstream head > tank head
                    status = StatType.TEMPCLOSED;
                }
            }

            // If tank empty, then prevent flow out of it
            if (tank.SimHead <= tank.Hmin + net.HTol)
            {
                // Case 1: Link is a pump discharging from tank
                if (Type == LinkType.PUMP)
                {
                    if (First == n1)
                    {
                        status = StatType.TEMPCLOSED;
                    }
                }
                // Case 2: Tank head > downstream head
                else if (CvStatus(net, StatType.CLOSED, h, q) == StatType.OPEN)
                {
                    status = StatType.TEMPCLOSED;
                }
            }
        }
예제 #5
0
            /// <summary>Checks if numerical condition on a variable is true.</summary>
            private bool CheckValue(FieldsMap fMap, double dsystem)
            {
                const double TOL = 0.001D;
                double       x;

                SimulationLink link = _object as SimulationLink;
                SimulationNode node = _object as SimulationNode;


                switch (_variable)
                {
                case Varwords.DEMAND:
                    if ((Objects)_object == Objects.SYSTEM)
                    {
                        x = dsystem * fMap.GetUnits(FieldType.DEMAND);
                    }
                    else
                    {
                        x = node.SimDemand * fMap.GetUnits(FieldType.DEMAND);
                    }

                    break;

                case Varwords.HEAD:
                case Varwords.GRADE:
                    x = node.SimHead * fMap.GetUnits(FieldType.HEAD);
                    break;

                case Varwords.PRESSURE:
                    x = (node.SimHead - node.Elevation) * fMap.GetUnits(FieldType.PRESSURE);
                    break;

                case Varwords.LEVEL:
                    x = (node.SimHead - node.Elevation) * fMap.GetUnits(FieldType.HEAD);
                    break;

                case Varwords.FLOW:
                    x = Math.Abs(link.SimFlow) * fMap.GetUnits(FieldType.FLOW);
                    break;

                case Varwords.SETTING:

                    if (double.IsNaN(link.SimSetting))
                    {
                        return(false);
                    }

                    x = link.SimSetting;
                    switch (link.Type)
                    {
                    case LinkType.PRV:
                    case LinkType.PSV:
                    case LinkType.PBV:
                        x *= fMap.GetUnits(FieldType.PRESSURE);
                        break;

                    case LinkType.FCV:
                        x *= fMap.GetUnits(FieldType.FLOW);
                        break;
                    }
                    break;

                case Varwords.FILLTIME: {
                    if (!(_object is SimulationTank))
                    {
                        return(false);
                    }

                    SimulationTank tank = (SimulationTank)_object;

                    if (tank.IsReservoir)
                    {
                        return(false);
                    }

                    if (tank.SimDemand <= Constants.TINY)
                    {
                        return(false);
                    }

                    x = (tank.Vmax - tank.SimVolume) / tank.SimDemand;

                    break;
                }

                case Varwords.DRAINTIME: {
                    if (!(_object is SimulationTank))
                    {
                        return(false);
                    }

                    SimulationTank tank = (SimulationTank)_object;

                    if (tank.IsReservoir)
                    {
                        return(false);
                    }

                    if (tank.SimDemand >= -Constants.TINY)
                    {
                        return(false);
                    }

                    x = (tank.Vmin - tank.SimVolume) / tank.SimDemand;
                    break;
                }

                default:
                    return(false);
                }

                switch (_relop)
                {
                case Operators.EQ:
                    if (Math.Abs(x - _value) > TOL)
                    {
                        return(false);
                    }
                    break;

                case Operators.NE:
                    if (Math.Abs(x - _value) < TOL)
                    {
                        return(false);
                    }
                    break;

                case Operators.LT:
                    if (x > _value + TOL)
                    {
                        return(false);
                    }
                    break;

                case Operators.LE:
                    if (x > _value - TOL)
                    {
                        return(false);
                    }
                    break;

                case Operators.GT:
                    if (x < _value - TOL)
                    {
                        return(false);
                    }
                    break;

                case Operators.GE:
                    if (x < _value + TOL)
                    {
                        return(false);
                    }
                    break;
                }
                return(true);
            }