Пример #1
0
        public static double CalculateEND(DepthFactor depthF, BreathGas gas)
        {
            var air   = new BreathGas();
            var ppN   = DivingMath.SeaLevelPreasureBars * BreathGas.GetGasPartialPreasureForDepth(depthF, gas.PpN);
            var depth = DivingMath.PreasureBarsToDepth(ppN / air.PpN, depthF.WaterDensity);

            return(Math.Round(depth.Depth, 1));
        }
Пример #2
0
        private void CalculateCompartmentPresures(double time, double depth, BreathGas gas, CompartmentCalculations[] tissues = null)
        {
            var    depthFact = new DepthFactor(depth, _waterDensity);
            double ppNitro   = gas.PpN * (BreathGas.GetGasPartialPreasureForDepth(depthFact, 1.0) - DivingMath.WaterVapourPreasureBars);
            double ppHe      = gas.PpHe * (BreathGas.GetGasPartialPreasureForDepth(depthFact, 1.0) - DivingMath.WaterVapourPreasureBars);

            int index = 0;

            foreach (var cpt in _compartments)
            {
                var data = (tissues ?? _compartmentData)[index];

                var n2Koef = 1.0 - Math.Pow(2.0, -time / cpt.N2HalfTime);
                var heKoef = 1.0 - Math.Pow(2.0, -time / cpt.HeHalfTime);

                data.N2Presure = data.N2Presure + ((ppNitro - data.N2Presure) * n2Koef);
                data.HePresure = data.HePresure + ((ppHe - data.HePresure) * heKoef);

                ++index;
            }
        }
Пример #3
0
 public GasModel(BreathGas gas)
 {
     PpO2 = Math.Round(gas.PpO * 100.0, 1);
     PpHe = Math.Round(gas.PpHe * 100.0, 1);
 }
Пример #4
0
        public CalculatedDivePlan Calculate(CalculatedDivePlan prevDive, DiveParameters diveParameters)
        {
            var    points       = new List <DivePlanPoint>(sizeof(double));
            var    bottomLevels = new List <LevelInfo>(diveParameters.Levels.Count());
            double totalTime    = 0;

            _diveParameters = diveParameters;

            var plan = new CalculatedDivePlan
            {
                MaxDepth       = _diveParameters.Levels.Max(l => l.DepthFactor.Depth),
                BottomTime     = _diveParameters.Levels.Sum(l => l.Time),
                PlanPoints     = points,
                MaxPpO         = _diveParameters.Levels.Max(l => BreathGas.GetGasPartialPreasureForDepth(l.DepthFactor, l.Gas.PpO)),
                MaxPpN         = _diveParameters.Levels.Max(l => BreathGas.GetGasPartialPreasureForDepth(l.DepthFactor, l.Gas.PpN)),
                DiveParameters = _diveParameters
            };

            var           diveResult = _diveAlgorythm.ProcessDive(_diveParameters, prevDive?.TissuesSaturationData);
            DivePlanPoint lastPoint  = null;

            if (diveResult.Errors?.Any() == true)
            {
                return new CalculatedDivePlan {
                           Errors = diveResult.Errors
                }
            }
            ;

            // dive start
            points.Add(new DivePlanPoint
            {
                Depth        = 0,
                AbsoluteTime = 0,
                Duration     = 0,
                Type         = DivePlanPointType.StartDive,
                Gas          = _diveParameters.Levels.First().Gas
            });

            lastPoint = points[0];

            foreach (var level in _diveParameters.Levels)
            {
                var depthDistance = Math.Abs(lastPoint.Depth - level.Depth);

                var descend = level.Depth > lastPoint.Depth;

                if (lastPoint.Type != DivePlanPointType.StartDive)
                {
                    lastPoint.Type = DivePlanPointType.Bottom | (descend ? DivePlanPointType.Descent : DivePlanPointType.Ascent);
                }

                var goToLevelTime = descend ?
                                    depthDistance / _diveParameters.DiveConfig.MaxDescentSpeed :
                                    depthDistance / _diveParameters.DiveConfig.MaxAscentSpeed;

                totalTime += goToLevelTime;
                var reachedTime = totalTime;

                points.Add(new DivePlanPoint
                {
                    Depth        = level.Depth,
                    AbsoluteTime = totalTime,
                    Duration     = goToLevelTime,
                    Gas          = level.Gas,
                    Type         = (descend ? DivePlanPointType.Descent : DivePlanPointType.Ascent) | DivePlanPointType.Bottom
                });

                totalTime += level.Time;

                points.Add(new DivePlanPoint
                {
                    Depth        = level.Depth,
                    AbsoluteTime = totalTime,
                    Duration     = level.Time,
                    Gas          = level.Gas,
                    Type         = DivePlanPointType.Bottom
                });

                bottomLevels.Add(new LevelInfo
                {
                    Depth       = level.Depth,
                    PpO         = BreathGas.GetGasPartialPreasureForDepth(level.DepthFactor, level.Gas.PpO),
                    END         = DivingMath.CalculateEND(level.DepthFactor, level.Gas),
                    Gas         = level.Gas,
                    TimeReached = reachedTime
                });

                lastPoint = points.Last();
            }

            lastPoint.Type = DivePlanPointType.Ascent | DivePlanPointType.Bottom | DivePlanPointType.FinalAscent;

            // ascend & deco
            if (diveResult.DecoStops?.Any() == true)
            {
                double lastDepth = lastPoint.Depth;

                foreach (var deco in diveResult.DecoStops)
                {
                    var decoAscendTime = (lastDepth - deco.Depth) / _diveParameters.DiveConfig.MaxAscentSpeed;
                    totalTime += decoAscendTime;

                    points.Add(new DivePlanPoint
                    {
                        Depth        = deco.Depth,
                        AbsoluteTime = totalTime,
                        Duration     = deco.Time,
                        Gas          = deco.Gas,
                        Type         = DivePlanPointType.Deco
                    });

                    totalTime += deco.Time;

                    points.Add(new DivePlanPoint
                    {
                        Depth        = deco.Depth,
                        AbsoluteTime = totalTime,
                        Duration     = deco.Time,
                        Gas          = deco.Gas,
                        Type         = DivePlanPointType.Deco | DivePlanPointType.FinalAscent
                    });

                    lastDepth = deco.Depth;
                }

                var ascendTime = lastDepth / _diveParameters.DiveConfig.MaxAscentSpeed;
                totalTime += ascendTime;
            }
            else
            {
                // ascend
                var ascendTime = (lastPoint.Depth - _diveParameters.DiveConfig.SafeStopDepth) / _diveParameters.DiveConfig.MaxAscentSpeed;
                totalTime += ascendTime;

                var avrAscDepth = (lastPoint.Depth + _diveParameters.DiveConfig.SafeStopDepth) / 2;

                if (lastPoint.Depth <= _diveParameters.DiveConfig.SafeStopDepth)
                {
                    // no safety stop
                    totalTime += lastPoint.Depth / _diveParameters.DiveConfig.MaxAscentSpeed;
                }
                else
                {
                    // safety stop
                    points.Add(new DivePlanPoint
                    {
                        Depth        = _diveParameters.DiveConfig.SafeStopDepth,
                        AbsoluteTime = totalTime,
                        Duration     = _diveParameters.DiveConfig.SafeStopTime,
                        Gas          = _diveParameters.Levels.First().Gas,
                        Type         = DivePlanPointType.SafeStop
                    });

                    totalTime += _diveParameters.DiveConfig.SafeStopTime;

                    points.Add(new DivePlanPoint
                    {
                        Depth        = _diveParameters.DiveConfig.SafeStopDepth,
                        AbsoluteTime = totalTime,
                        Duration     = _diveParameters.DiveConfig.SafeStopTime,
                        Gas          = _diveParameters.Levels.First().Gas,
                        Type         = DivePlanPointType.SafeStop | DivePlanPointType.FinalAscent
                    });

                    ascendTime = _diveParameters.DiveConfig.SafeStopDepth / _diveParameters.DiveConfig.MaxAscentSpeed;
                    totalTime += ascendTime;
                }
            }

            // end dive
            points.Add(new DivePlanPoint {
                Depth = 0, AbsoluteTime = totalTime, Type = DivePlanPointType.EndDive, Gas = new BreathGas()
            });

            var gasSwitches = new List <GasSwitch>();

            plan.FullDesaturationTime   = diveResult.FullDesaturationTime;
            plan.TissuesSaturationData  = diveResult.TissuesSaturationData;
            plan.TotalTime              = diveResult.DiveTotalTime;
            plan.MaxNoDecoDepthTime     = diveResult.MaxNoDecoDepthTime;
            plan.DynamicNoDecoDepthTime = diveResult.DynamicNoDecoDepthTime;
            plan.IntervalTime           = _diveParameters.IntervalTime;
            plan.OxygenCns              = OxygenToxicityCalculator.CalulateOxygenCns(diveResult.DivePoints);
            plan.MaxEND      = _diveParameters.Levels.Max(l => DivingMath.CalculateEND(l.DepthFactor, l.Gas));
            plan.GasSwitches = gasSwitches;
            plan.LevelsInfo  = bottomLevels;

            foreach (var level in _diveParameters.Levels.Skip(1))
            {
                // use strict reference comparsion for presise gas check
                var gasSwitchPoint = diveResult.DivePoints.FirstOrDefault(d => d.CurrentGas == level.Gas);
                if (!gasSwitchPoint.IsEmpty())
                {
                    gasSwitches.Add(new GasSwitch
                    {
                        Depth        = gasSwitchPoint.DepthFactor.Depth,
                        AbsoluteTime = gasSwitchPoint.CurrentDiveTime,
                        Gas          = gasSwitchPoint.CurrentGas,
                        IsDeco       = false,
                        PpO          = BreathGas.GetGasPartialPreasureForDepth(gasSwitchPoint.DepthFactor, gasSwitchPoint.CurrentGas.PpO)
                    });
                }
            }

            foreach (var decoLevel in _diveParameters.DecoLevels ?? new List <DiveLevel>())
            {
                // use strict reference comparsion for presise gas check
                var decoGasSwitchPoint = diveResult.DivePoints.FirstOrDefault(d => d.CurrentGas == decoLevel.Gas);
                if (!decoGasSwitchPoint.IsEmpty())
                {
                    gasSwitches.Add(new GasSwitch
                    {
                        Depth        = decoGasSwitchPoint.DepthFactor.Depth,
                        AbsoluteTime = decoGasSwitchPoint.CurrentDiveTime,
                        Gas          = decoGasSwitchPoint.CurrentGas,
                        IsDeco       = true,
                        PpO          = BreathGas.GetGasPartialPreasureForDepth(decoGasSwitchPoint.DepthFactor, decoGasSwitchPoint.CurrentGas.PpO)
                    });
                }
            }

            // celing points reduce logic
            if (diveResult.CeilingDepthPoints?.Any() == true)
            {
                const int maxPoints = 100;
                var       skip      = 2 * diveResult.CeilingDepthPoints.Count() / 2 / maxPoints;
                if (skip == 0)
                {
                    skip = 1;
                }

                var ceilingDepthPoints = new List <DepthTime>(diveResult.CeilingDepthPoints.Count() / skip);

                var count = diveResult.CeilingDepthPoints.Count();
                for (int i = 0; i < count; i++)
                {
                    if (i % skip == 0)
                    {
                        var elem = diveResult.CeilingDepthPoints.ElementAt(i);
                        ceilingDepthPoints.Add(new DepthTime(elem.Depth, elem.Time));
                    }
                }

                ceilingDepthPoints.Add(new DepthTime(0, diveResult.CeilingDepthPoints.Last().Time));
                plan.CeilingDepthPoints = ceilingDepthPoints;
            }

            var consumedGas = CalculateConsumedGas(diveResult, gasSwitches);

            plan.ConsumedBottomGases = consumedGas.Key;
            plan.ConsumedDecoGases   = consumedGas.Value;
            plan.DiveResultBlocks    = plan.GetDiveInfo();

            return(plan);
        }
Пример #5
0
        public static double CalulateOxygenCns(IEnumerable <DivePoint> divePoints)
        {
            double    cns       = 0;
            DivePoint?prevPoint = null;

            foreach (var point in divePoints)
            {
                if (prevPoint.HasValue)
                {
                    var timeExposure = point.CurrentDiveTime - prevPoint.Value.CurrentDiveTime;
                    var avgDepth     = (prevPoint.Value.DepthFactor.Depth + point.DepthFactor.Depth) * 0.5;
                    var ambPreasure  = BreathGas.GetGasPartialPreasureForDepth(new DepthFactor(avgDepth, point.DepthFactor.WaterDensity), 1.0);
                    var ppO2         = point.CurrentGas.PpO * (ambPreasure - DivingMath.WaterVapourPreasureBars);

                    if (ppO2 >= _cnsTable.Last().PpO)
                    {
                        int ind = -1;
                        for (int i = 1; i < _cnsTable.Length; i++)
                        {
                            if (ppO2 > _cnsTable[i].PpO)
                            {
                                ind = i - 1;
                                break;
                            }
                        }

                        if (ind < 0)
                        {
                            ind = _cnsTable.Length - 1;
                        }

                        var cnsRecord = _cnsTable[ind];
                        var cnsValue  = cnsRecord.Exposure;

                        if (ppO2 > _cnsTable.First().PpO)
                        {
                            cnsValue = _cnsTable.First().Exposure;
                        }
                        else if (ind < (_cnsTable.Length - 1))
                        {
                            var prevRecord = _cnsTable[ind + 1];
                            var deltaPpO2  = ppO2 - prevRecord.PpO;
                            if (deltaPpO2 > 0)
                            {
                                // interpolate
                                var recordsDelta = Math.Abs(cnsRecord.PpO - prevRecord.PpO);
                                var offset       = deltaPpO2 / recordsDelta;

                                cnsValue = offset * cnsRecord.Exposure + (1.0 - offset) * prevRecord.Exposure;
                            }
                        }

                        cns += timeExposure / cnsValue * 100.0;
                    }
                }

                prevPoint = point;
            }


            return(Math.Round(cns, 1));
        }
Пример #6
0
        public Zhl16Algorithm()
        {
            _compartmentTables = new Dictionary <SubType, List <Compartment> >();

            //TODO: add helium values
            _compartmentTables[SubType.A] = new List <Compartment>
            {
                new Compartment {
                    N2HalfTime = 4, N2ValueA = 1.2599, N2ValueB = 0.5050
                },
                new Compartment {
                    N2HalfTime = 8, N2ValueA = 1.0000, N2ValueB = 0.6514
                },
                new Compartment {
                    N2HalfTime = 12.5, N2ValueA = 0.8618, N2ValueB = 0.7222
                },
                new Compartment {
                    N2HalfTime = 18.5, N2ValueA = 0.7562, N2ValueB = 0.7725
                },
                new Compartment {
                    N2HalfTime = 27, N2ValueA = 0.6667, N2ValueB = 0.8125
                },
                new Compartment {
                    N2HalfTime = 38.3, N2ValueA = 0.5933, N2ValueB = 0.8434
                },
                new Compartment {
                    N2HalfTime = 54.3, N2ValueA = 0.5282, N2ValueB = 0.8693
                },
                new Compartment {
                    N2HalfTime = 77, N2ValueA = 0.4701, N2ValueB = 0.8910
                },
                new Compartment {
                    N2HalfTime = 109, N2ValueA = 0.4187, N2ValueB = 0.9092
                },
                new Compartment {
                    N2HalfTime = 146, N2ValueA = 0.3798, N2ValueB = 0.9222
                },
                new Compartment {
                    N2HalfTime = 187, N2ValueA = 0.3497, N2ValueB = 0.9319
                },
                new Compartment {
                    N2HalfTime = 239, N2ValueA = 0.3223, N2ValueB = 0.9403
                },
                new Compartment {
                    N2HalfTime = 305, N2ValueA = 0.2971, N2ValueB = 0.9477
                },
                new Compartment {
                    N2HalfTime = 390, N2ValueA = 0.2737, N2ValueB = 0.9544
                },
                new Compartment {
                    N2HalfTime = 498, N2ValueA = 0.2523, N2ValueB = 0.9602
                },
                new Compartment {
                    N2HalfTime = 635, N2ValueA = 0.2327, N2ValueB = 0.9653
                }
            };

            //TODO: add helium values
            _compartmentTables[SubType.B] = new List <Compartment>
            {
                new Compartment {
                    N2HalfTime = 4, N2ValueA = 1.2599, N2ValueB = 0.5050
                },
                //new Compartment { N2HalfTime = 5, N2ValueA = 1.1696, N2ValueB = 0.5578 },
                new Compartment {
                    N2HalfTime = 8, N2ValueA = 1.0000, N2ValueB = 0.6514
                },
                new Compartment {
                    N2HalfTime = 12.5, N2ValueA = 0.8618, N2ValueB = 0.7222
                },
                new Compartment {
                    N2HalfTime = 18.5, N2ValueA = 0.7562, N2ValueB = 0.7825
                },
                new Compartment {
                    N2HalfTime = 27, N2ValueA = 0.6667, N2ValueB = 0.8126
                },
                new Compartment {
                    N2HalfTime = 38.3, N2ValueA = 0.5600, N2ValueB = 0.8434
                },
                new Compartment {
                    N2HalfTime = 54.3, N2ValueA = 0.4947, N2ValueB = 0.8693
                },
                new Compartment {
                    N2HalfTime = 77, N2ValueA = 0.4500, N2ValueB = 0.8910
                },
                new Compartment {
                    N2HalfTime = 109, N2ValueA = 0.4187, N2ValueB = 0.9092
                },
                new Compartment {
                    N2HalfTime = 146, N2ValueA = 0.3798, N2ValueB = 0.9222
                },
                new Compartment {
                    N2HalfTime = 187, N2ValueA = 0.3497, N2ValueB = 0.9319
                },
                new Compartment {
                    N2HalfTime = 239, N2ValueA = 0.3223, N2ValueB = 0.9403
                },
                new Compartment {
                    N2HalfTime = 305, N2ValueA = 0.2850, N2ValueB = 0.9477
                },
                new Compartment {
                    N2HalfTime = 390, N2ValueA = 0.2737, N2ValueB = 0.9544
                },
                new Compartment {
                    N2HalfTime = 498, N2ValueA = 0.2523, N2ValueB = 0.9602
                },
                new Compartment {
                    N2HalfTime = 635, N2ValueA = 0.2327, N2ValueB = 0.9653
                }
            };

            _compartmentTables[SubType.C] = new List <Compartment>
            {
                new Compartment {
                    N2HalfTime = 4, N2ValueA = 1.2599, N2ValueB = 0.5050, HeHalfTime = 1.51, HeValueA = 1.7424, HeValueB = 0.4245
                },
                new Compartment {
                    N2HalfTime = 8, N2ValueA = 1.0000, N2ValueB = 0.6514, HeHalfTime = 3.02, HeValueA = 1.3830, HeValueB = 0.5747
                },
                new Compartment {
                    N2HalfTime = 12.5, N2ValueA = 0.8618, N2ValueB = 0.7222, HeHalfTime = 4.72, HeValueA = 1.1919, HeValueB = 0.6527
                },
                new Compartment {
                    N2HalfTime = 18.5, N2ValueA = 0.7562, N2ValueB = 0.7725, HeHalfTime = 6.99, HeValueA = 1.0458, HeValueB = 0.7223
                },
                new Compartment {
                    N2HalfTime = 27, N2ValueA = 0.6200, N2ValueB = 0.8125, HeHalfTime = 10.21, HeValueA = 0.9220, HeValueB = 0.7582
                },
                new Compartment {
                    N2HalfTime = 38.3, N2ValueA = 0.5043, N2ValueB = 0.8434, HeHalfTime = 14.48, HeValueA = 0.8205, HeValueB = 0.7957
                },
                new Compartment {
                    N2HalfTime = 54.3, N2ValueA = 0.4410, N2ValueB = 0.8693, HeHalfTime = 20.53, HeValueA = 0.7305, HeValueB = 0.8279
                },
                new Compartment {
                    N2HalfTime = 77, N2ValueA = 0.4000, N2ValueB = 0.8910, HeHalfTime = 29.11, HeValueA = 0.6502, HeValueB = 0.8553
                },
                new Compartment {
                    N2HalfTime = 109, N2ValueA = 0.3750, N2ValueB = 0.9092, HeHalfTime = 41.20, HeValueA = 0.5950, HeValueB = 0.8757
                },
                new Compartment {
                    N2HalfTime = 146, N2ValueA = 0.3500, N2ValueB = 0.9222, HeHalfTime = 55.19, HeValueA = 0.5545, HeValueB = 0.8903
                },
                new Compartment {
                    N2HalfTime = 187, N2ValueA = 0.3295, N2ValueB = 0.9319, HeHalfTime = 70.69, HeValueA = 0.5333, HeValueB = 0.8997
                },
                new Compartment {
                    N2HalfTime = 239, N2ValueA = 0.3065, N2ValueB = 0.9403, HeHalfTime = 90.34, HeValueA = 0.5189, HeValueB = 0.9073
                },
                new Compartment {
                    N2HalfTime = 305, N2ValueA = 0.2835, N2ValueB = 0.9477, HeHalfTime = 115.29, HeValueA = 0.5181, HeValueB = 0.9122
                },
                new Compartment {
                    N2HalfTime = 390, N2ValueA = 0.2610, N2ValueB = 0.9544, HeHalfTime = 147.42, HeValueA = 0.5176, HeValueB = 0.9171
                },
                new Compartment {
                    N2HalfTime = 498, N2ValueA = 0.2480, N2ValueB = 0.9602, HeHalfTime = 188.24, HeValueA = 0.5172, HeValueB = 0.9217
                },
                new Compartment {
                    N2HalfTime = 635, N2ValueA = 0.2327, N2ValueB = 0.9653, HeHalfTime = 240.03, HeValueA = 0.5119, HeValueB = 0.9267
                }
            };

            _airGas = new BreathGas();
            var tableSize = _compartmentTables.Values.Max(t => t.Count);

            _compartmentData    = new CompartmentCalculations[tableSize];
            _compartmentAltData = new CompartmentCalculations[tableSize];

            for (int i = 0; i < _compartmentData.Length; i++)
            {
                _compartmentAltData[i] = new CompartmentCalculations();
                _compartmentData[i]    = new CompartmentCalculations();
            }
        }
Пример #7
0
        private void AddDivePointInfo(double time, double celingDepth, double currDepth, BreathGas gas, bool forceAdd = false)
        {
            if (TimeSpan.FromMinutes(time - _trackedDivePointTime).TotalSeconds >= 5 || time <= double.Epsilon || forceAdd)
            {
                _mValues.Add(new DepthTime(celingDepth, time));
                _divePoints.Add(new DivePoint
                {
                    DepthFactor     = new DepthFactor(currDepth, _waterDensity),
                    CurrentDiveTime = time,
                    CurrentGas      = gas
                });

                _trackedDivePointTime = time;
            }
        }
Пример #8
0
        private BreathGas SelectDecoGas(DepthFactor currDepth, double decoStopDepth)
        {
            const double MaxDecoPpO     = 1.6;
            const double OptimalDecoPpO = 1.5;

            if ((_diveParameters.DecoLevels?.Count() ?? 0) == 0)
            {
                return(_diveParameters.Levels.Last().Gas);
            }

            var decoPpO = MaxDecoPpO;

            if ((currDepth.Depth - decoStopDepth) > (DecoStopsStep + double.Epsilon))
            {
                decoPpO = OptimalDecoPpO;
            }

            var gasesCanUse = new List <KeyValuePair <double, BreathGas> >(_diveParameters.DecoLevels.Count());

            // explicit depth gases go first
            var explicitDepthGases = _diveParameters.DecoLevels.Where(d => d.Depth > double.Epsilon);

            if (explicitDepthGases.Any())
            {
                var suitedDecoGases = explicitDepthGases.Where(d => currDepth.Depth <= d.Depth);
                if (!suitedDecoGases.Any())
                {
                    return(_diveParameters.Levels.Last().Gas);
                }

                var minDepth        = explicitDepthGases.Where(d => currDepth.Depth <= d.Depth).Min(d => d.Depth);
                var explicitDecoGas = explicitDepthGases.FirstOrDefault(d => DivingMath.CompareDouble(d.Depth, minDepth));

                if (explicitDecoGas != null)
                {
                    return(explicitDecoGas.Gas);
                }
                else
                {
                    return(_diveParameters.Levels.Last().Gas);
                }
            }
            else
            {
                foreach (var decoLevel in _diveParameters.DecoLevels)
                {
                    var currDecoPpO = BreathGas.GetGasPartialPreasureForDepth(currDepth, decoLevel.Gas.PpO);
                    if (currDecoPpO <= decoPpO)
                    {
                        gasesCanUse.Add(new KeyValuePair <double, BreathGas>(currDecoPpO, decoLevel.Gas));
                    }
                }

                if (gasesCanUse.Count == 0)
                {
                    return(_diveParameters.Levels.Last().Gas);
                }

                return(gasesCanUse.First(g => DivingMath.CompareDouble(g.Key, gasesCanUse.Max(k => k.Key))).Value);
            }
        }