public void DiveProfile_CalcGradient_CurrentDepthInTheMidleOfDecoAndGradientGoingUp()
 {
     var pref = new Preference();
     pref.LowGradient = 1;
     pref.HighGradient = 2;
     pref.DepthBetweenDecoStops = 3;
     double currentDepth = 6;
     double expected = 1.5;
     double actual;
     actual = DiveProfile.CalcGradient(9, currentDepth, pref);
     Assert.Equal(expected, actual);
 }
        public static double CalcGradient(double firstDecoDepth, double currentDepth, Preference pref)
        {
            if (Math.Abs(firstDecoDepth - 0) > 0.001)
            {
                double numberOfStops = firstDecoDepth/pref.DepthBetweenDecoStops;
                double currentStep = ((firstDecoDepth - currentDepth)/pref.DepthBetweenDecoStops) + 1;

                // if only one stop then always lowgradient
                if (numberOfStops == 1)
                {
                    return pref.LowGradient;
                }

                // if only two stop and current step is first stop then low gradient
                if (numberOfStops == 2 && currentStep == 1)
                {
                    return pref.LowGradient;
                }

                // if only two stop and current step is last stop then high gradient
                if (numberOfStops == 2 && currentStep == 2)
                {
                    return pref.HighGradient;
                }

                // last stop
                if (numberOfStops == currentStep)
                {
                    return pref.HighGradient;
                }

                // first stop
                if (currentStep == 1)
                {
                    return pref.LowGradient;
                }

                double gradientStepSize = Math.Abs(pref.HighGradient - pref.LowGradient)/(numberOfStops - 1);

                bool increasingGradient = !(pref.HighGradient < pref.LowGradient);

                if (increasingGradient)
                {
                    return ((currentStep - 1)*gradientStepSize) + pref.LowGradient;
                }

                return ((currentStep - 1)*gradientStepSize) + pref.HighGradient;
            }

            return pref.LowGradient;
        }
        public static double GetDecoDepth(double depth, Preference pref)
        {
            var fac = (int) Math.Ceiling(depth/pref.DepthBetweenDecoStops);

            depth = fac*pref.DepthBetweenDecoStops;

            // Ensure that we don't go above min deco depth
            if (depth < pref.MiniDepthForDeco)
            {
                Logger.Trace(
                    "GetDecoDepth => New deco depth ({0}) is smaller then mini depth for deco. Setting deco depth to min value:{1}",
                    depth, pref.MiniDepthForDeco);
                depth = pref.MiniDepthForDeco;
            }

            return depth;
        }
        private static int GetDecoStopTime(ZH_L16 alg, double depth, Preference pref, double gradient)
        {
            int timer = 0;
            double goalDepth = depth - pref.DepthBetweenDecoStops;

            //// If goal depth is small the min depth for deco and depth is equal to mino deco depth set next deco depth to 0.
            if (goalDepth < pref.MiniDepthForDeco && Math.Abs(depth - pref.MiniDepthForDeco) < 0.001)
            {
                Logger.Trace(
                    "GetDecoStopTime => Goal depth ({0}) is smaller then mini deco depth {1} for deco, on current depth ({2}) is equal to mini deco depth. Setting goal depth to 0",
                    goalDepth, pref.MiniDepthForDeco, depth);
                goalDepth = 0;
            }

            //// If goal deth is small the min depth for deco and depth is bigger that mini deco depth set next deco depth to mnin deco depth.
            if (goalDepth < pref.MiniDepthForDeco && depth > pref.MiniDepthForDeco)
            {
                Logger.Trace(
                    "GetDecoStopTime => Goal depth ({0}) is smaller then mini deco depth {1} for deco, on current depth ({2}) and depth is bigger than mini deco depth. Setting goal depth to min deco depth",
                    goalDepth, pref.MiniDepthForDeco, depth);
                goalDepth = pref.MiniDepthForDeco;
            }

            double startDepth = depth;
            while (goalDepth < depth)
            {
                timer++;
                alg.AddRunTimeInMinutes(1, startDepth);
                depth = alg.MinDepthAscent(gradient);
            }

            Logger.Trace("GetDecoStopTime => StartDepth:{0}, EndDepth:{1}, Gradient:{2}, Time:{3}", startDepth, depth,
                         gradient, timer);
            return timer;
        }
        public Collection<DiveSegment> Calc(Collection<WayPoint> waypoints, ZH_L16 algorithm, Preference preference)
        {
            pref = preference;

            var divetable = new Collection<DiveSegment>();
            int runTime = 0;
            double depth = 0;
            if (algorithm.ActiveGas == null)
            {
                algorithm.ActiveGas = waypoints[0].Gas;
            }

            foreach (WayPoint waypoint in waypoints)
            {
                var ascdescTime = new TimeSpan();

                //// Going down
                if (waypoint.Depth > depth)
                {
                    ascdescTime = GoingDown(algorithm, ref divetable, runTime, depth, waypoint);
                }

                //// Going upp
                if (waypoint.Depth < depth)
                {
                    ascdescTime = GoingUp(algorithm, ref divetable, runTime, depth, waypoint);
                }

                int timeSpentAscDesc = TimeHelper.MinutesRoundedUp(ascdescTime);
                runTime += timeSpentAscDesc;

                // Gas swith
                if (!Equals(algorithm.ActiveGas, waypoint.Gas))
                {
                    if (this.pref.TimeToSwitchGas > 0)
                    {
                        algorithm.AddRunTimeInMinutes(pref.TimeToSwitchGas, waypoint.Depth);
                    }

                    double cns = CentralNervousSystem.ConstantDepth(algorithm.ActiveGas, waypoint.Depth, pref.TimeToSwitchGas);
                    double otu = OxygenToxicityUnit.ConstantDepth(algorithm.ActiveGas, waypoint.Depth, pref.TimeToSwitchGas);
                    var seg = new DiveSegment(waypoint.Depth, new TimeSpan(0, 0, (int) pref.TimeToSwitchGas, 0, 0),
                                              DiveState.GasSwitch, runTime, runTime + (int) pref.TimeToSwitchGas,
                                              algorithm.ActiveGas, cns, otu);
                    Logger.Trace("Calc => Segment:" + seg);
                    divetable.Add(seg);
                    runTime += (int) pref.TimeToSwitchGas;
                    algorithm.ActiveGas = waypoint.Gas;
                }

                //// still time left to stay at depth
                if (timeSpentAscDesc < waypoint.Time)
                {
                    double timeLeft = waypoint.Time - timeSpentAscDesc;
                    StayAtDepth(algorithm, ref divetable, runTime, waypoint.Depth, timeLeft);
                    runTime += (int) waypoint.Time - timeSpentAscDesc;
                }

                depth = waypoint.Depth;
            }

            return divetable;
        }
 public void DiveProfile_CalcGradient_FourDecoStopAndOnFirstMidle()
 {
     var pref = new Preference();
     pref.LowGradient = 1;
     pref.HighGradient = 2;
     pref.DepthBetweenDecoStops = 3;
     double currentDepth = 9;
     double expected = 1.33;
     double actual;
     actual = Math.Round(DiveProfile.CalcGradient(12, currentDepth, pref), 2);
     Assert.Equal(expected, actual);
 }
 public void DiveProfile_GetDecoDepth_OneMeterFromLower()
 {
     double depth = 7;
     Preference pref = new Preference();
     pref.DepthBetweenDecoStops = 3;
     pref.MiniDepthForDeco = 3;
     double expected = 9;
     double actual;
     actual = DiveProfile.GetDecoDepth(depth, pref);
     Assert.Equal(expected, actual);
 }
 public void DiveProfile_GetDecoDepth_BelowMinimumDecoDepthAfterCalc()
 {
     double depth = 3;
     Preference pref = new Preference();
     pref.DepthBetweenDecoStops = 4;
     pref.MiniDepthForDeco = 8;
     double expected = 8;
     double actual;
     actual = DiveProfile.GetDecoDepth(depth, pref);
     Assert.Equal(expected, actual);
 }
 public void DiveProfile_CalcGradient_TwoDecoStopAndOnLast()
 {
     var pref = new Preference();
     pref.LowGradient = 1;
     pref.HighGradient = 2;
     pref.DepthBetweenDecoStops = 3;
     double currentDepth = 3;
     double expected = 2;
     double actual;
     actual = DiveProfile.CalcGradient(6, currentDepth, pref);
     Assert.Equal(expected, actual);
 }
 public void DiveProfile_CalcGradient_NotDecoDepth()
 {
     var pref = new Preference();
     pref.LowGradient = 2;
     pref.HighGradient = 1;
     double currentDepth = 50;
     double expected = 2;
     double actual;
     actual = DiveProfile.CalcGradient(0, currentDepth, pref);
     Assert.Equal(expected, actual);
 }