private KeyValuePair <IEnumerable <ConsumedGas>, IEnumerable <ConsumedGas> > CalculateConsumedGas(
            CalculatedDiveResult diveResult, IEnumerable <GasSwitch> gasSwitches)
        {
            DivePoint?prevPoint   = null;
            var       bottomGases = new Dictionary <BreathGas, ConsumedGas>(sizeof(double));
            var       decoGases   = new Dictionary <BreathGas, ConsumedGas>(sizeof(double));

            var firstStopDepth = diveResult.DecoStops?.Any() == true?diveResult.DecoStops.Max(s => s.Depth) : 0;

            if (firstStopDepth < double.Epsilon)
            {
                firstStopDepth = _diveParameters.DiveConfig.SafeStopDepth;
            }

            foreach (var point in diveResult.DivePoints)
            {
                if (prevPoint != null)
                {
                    var avgDepth = (prevPoint.Value.DepthFactor.Depth + point.DepthFactor.Depth) * 0.5;
                    if (avgDepth <= double.Epsilon)
                    {
                        break;
                    }

                    var timeSpan = point.CurrentDiveTime - prevPoint.Value.CurrentDiveTime;
                    if (timeSpan > 0)
                    {
                        var preasure = DivingMath.DepthToPreasureBars(new DepthFactor(avgDepth, point.DepthFactor.WaterDensity));
                        var rmv      = (avgDepth <= firstStopDepth) ? _diveParameters.DiveConfig.DecoRmv : _diveParameters.DiveConfig.BottomRmv;

                        var decoSwitchTime = gasSwitches.FirstOrDefault(gs => gs.IsDeco)?.AbsoluteTime ?? 0.0;
                        var gases          = (point.CurrentDiveTime >= decoSwitchTime && decoSwitchTime > double.Epsilon) ? decoGases : bottomGases;

                        if (!gases.ContainsKey(point.CurrentGas))
                        {
                            gases[point.CurrentGas] = new ConsumedGas()
                            {
                                Gas = point.CurrentGas
                            }
                        }
                        ;

                        gases[point.CurrentGas].Amount += rmv * preasure / DivingMath.SeaLevelPreasureBars * timeSpan;
                    }
                }

                prevPoint = point;
            }

            return(new KeyValuePair <IEnumerable <ConsumedGas>, IEnumerable <ConsumedGas> >(bottomGases.Values, decoGases.Values));
        }
    }
示例#2
0
        public CalculatedDiveResult ProcessDive(DiveParameters diveParameters, object tissuePreasures = null)
        {
            Reset(diveParameters, tissuePreasures);

            double totalTime              = 0;
            double currentDepth           = 0;
            double maxDepth               = diveParameters.Levels.Max(l => l.Depth);
            var    dynamicNoDecoDepthTime = new DepthTime();
            var    levelGas               = diveParameters.Levels.First().Gas;

            AddDivePointInfo(totalTime, 0, 0, _diveParameters.Levels.First().Gas, true);

            // dive
            foreach (var level in diveParameters.Levels)
            {
                var    descent          = currentDepth < level.Depth;
                bool   levelReached     = false;
                double levelReachedTime = 0;

                while (true)
                {
                    if (descent)
                    {
                        currentDepth += TimeStep * diveParameters.DiveConfig.MaxDescentSpeed;
                        if (currentDepth > level.Depth)
                        {
                            currentDepth = level.Depth;
                        }
                    }
                    else
                    {
                        currentDepth -= TimeStep * diveParameters.DiveConfig.MaxAscentSpeed;
                        if (currentDepth < level.Depth)
                        {
                            currentDepth = level.Depth;
                        }
                    }

                    if (!levelReached && currentDepth > (level.Depth - 0.1) && currentDepth < (level.Depth + 0.1))
                    {
                        levelGas         = level.Gas;
                        levelReached     = true;
                        levelReachedTime = totalTime;
                    }

                    CalculateCompartmentPresures(TimeStep, currentDepth, levelGas);
                    var ceilingDepth = GetCurrentCeilingDepth(currentDepth);
                    if (currentDepth < ceilingDepth)
                    {
                        throw new Exception("Levels' depth above deco depth");
                    }

                    var noDecoCeilingDepth = GetCurrentCeilingDepth(currentDepth, _diveParameters.DiveConfig.GradFactorHigh);
                    if (noDecoCeilingDepth > double.Epsilon && dynamicNoDecoDepthTime.Time < double.Epsilon)
                    {
                        // no deco limit
                        dynamicNoDecoDepthTime = new DepthTime(currentDepth, totalTime);
                    }

                    totalTime += TimeStep;
                    AddDivePointInfo(totalTime, ceilingDepth, currentDepth, levelGas);

                    if (levelReached && (totalTime - levelReachedTime) >= level.Time)
                    {
                        break;
                    }
                }
            }

            var maxNoDecoTime = CalculateMaxNoDecoTime(maxDepth);
            IEnumerable <DiveLevel> decoStops = null;

            // ascent
            if (currentDepth <= diveParameters.DiveConfig.SafeStopDepth)
            {
                //no need even safety stop
                while (true)
                {
                    currentDepth -= TimeStep * _diveParameters.DiveConfig.MaxAscentSpeed;
                    if (currentDepth < double.Epsilon)
                    {
                        break;
                    }

                    CalculateCompartmentPresures(TimeStep, currentDepth, diveParameters.Levels.First().Gas);
                    totalTime += TimeStep;
                }

                AddDivePointInfo(totalTime, 0, 0, diveParameters.Levels.First().Gas, true);
            }
            else
            {
                var decoStopDepth = FindNearestDecoDepth(GetCurrentCeilingDepth(currentDepth));
                if (decoStopDepth > 0 && GetCurrentCeilingDepth(currentDepth, _diveParameters.DiveConfig.GradFactorHigh) > 0)
                {
                    var ascentResult = AscentWithDeco(currentDepth, totalTime);
                    totalTime = ascentResult.Key;
                    decoStops = ascentResult.Value;
                }
                else
                {
                    totalTime = AscentWithoutDeco(currentDepth, totalTime);
                }
            }

            var tissueData = _compartmentData.Select(c => new AlgoResult {
                N2Presure = c.N2Presure, HePresure = c.HePresure
            }).ToArray();

            var result = new CalculatedDiveResult
            {
                MaxAscendSpeed         = diveParameters.DiveConfig.MaxAscentSpeed,
                MaxNoDecoDepthTime     = new DepthTime(maxDepth, maxNoDecoTime),
                DynamicNoDecoDepthTime = dynamicNoDecoDepthTime,
                SaturationIndex        = 0,
                DecoStops             = decoStops,
                CeilingDepthPoints    = _mValues,
                FullDesaturationTime  = CalculateFullDesaturationTime(),
                DivePoints            = _divePoints,
                DiveTotalTime         = totalTime,
                TissuesSaturationData = tissueData
            };

            return(result);
        }