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)); } }
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); }