public CanalData ExecuteCanalSimulation() { // Coordinate and sync calls to make sure no race conditions and odd stuff can happen in sync CanalSimulationResult canalSimulationResult = Canal.ExecuteCanalSimulation(); return(new CanalData(Canal, canalSimulationResult)); }
/// <summary> /// Executes the canal simulation /// </summary> /// <returns></returns> public CanalSimulationResult ExecuteCanalSimulation() { var result = new CanalSimulationResult(); RungeKutta solver = new RungeKutta(); double flow = CanalStretches.Where(cs => cs.Flow > 0).Select(cs => cs.Flow).FirstOrDefault(); if (!(flow > 0)) { flow = CanelEdges.OfType <SluiceCanalEdge>().Select(sce => sce.GetFreeFlow).FirstOrDefault(); } CanalStretches.ForEach(cs => cs.Flow = flow); foreach (ICanalStretchModel canalStretch in CanalStretches) { CanalStretchResult canalStretchResult = result.GetCanalStretchResult(canalStretch.Id); canalStretchResult.CriticalSlope = canalStretch.CanalSection.GetCriticalSlope(canalStretch.Flow); canalStretchResult.CriticalWaterLevel = canalStretch.CanalSection.GetCriticalWaterLevel(canalStretch.Flow); canalStretchResult.NormalWaterLevel = canalStretch.CanalSection.GetNormalWaterLevel(canalStretch.Flow); ICanalStretchModel preCanalStretch = CanalStretches.FirstOrDefault(cs => cs.ToNode.Id == canalStretch.FromNode.Id); ICanalStretchModel postCanalStretch = CanalStretches.FirstOrDefault(cs => cs.FromNode.Id == canalStretch.ToNode.Id); bool postCriticalSection = false; if (preCanalStretch != null) { } if (postCanalStretch != null) { double normalWaterLevel = postCanalStretch.CanalSection.GetNormalWaterLevel(postCanalStretch.Flow); postCriticalSection = normalWaterLevel <= canalStretchResult.CriticalWaterLevel; } AnalysisOptions options = new AnalysisOptions(); options.AnalysisSteps = (int)(canalStretch.Length > 10000 ? 10000 : canalStretch.Length); // M flow if (canalStretch.CanalSection.Slope > 0 && canalStretch.CanalSection.Slope < canalStretchResult.CriticalSlope) { // M1 // Regimen lento se impone aguas abajo if (canalStretch.ToNode.WaterLevel.HasValue && canalStretch.ToNode.WaterLevel.Value > canalStretchResult.CriticalWaterLevel) { options.InitialX = GetAbsoluteInitialLength(CanalStretches, canalStretch) + canalStretch.Length; options.FinalWaterLevel = canalStretch.ToNode.WaterLevel.Value; options.BackwardsAnalysis = true; options.ExecuteAnalysis = true; } // M2 Flow // Regimen lento se impone aguas abajo else if (postCriticalSection) { canalStretch.ToNode.WaterLevel = canalStretchResult.CriticalWaterLevel; options.InitialX = GetAbsoluteInitialLength(CanalStretches, canalStretch) + canalStretch.Length; options.FinalWaterLevel = canalStretchResult.CriticalWaterLevel + Sensibility /* Salvando numéricamente por la izquierda el problema */; options.BackwardsAnalysis = true; options.ExecuteAnalysis = true; } // M3 Flow // Regimen rapido se impone aguas arriba if (canalStretch.FromNode.WaterLevel.HasValue && canalStretch.FromNode.WaterLevel.Value < canalStretchResult.CriticalWaterLevel) { // Hydraulic jump will occur as we have in the same stretch both conditions for both flows options.HydraulicJumpOccurs = options.ExecuteAnalysis; options.InitialX = GetAbsoluteInitialLength(CanalStretches, canalStretch) + 0.0; options.InitialWaterLevel = canalStretch.FromNode.WaterLevel.Value; options.BackwardsAnalysis = false; options.ExecuteAnalysis = true; } } // S flow else if (canalStretch.CanalSection.Slope > canalStretchResult.CriticalSlope) { // S1 Flow // Regimen lento se impone aguas abajo if (canalStretch.ToNode.WaterLevel.HasValue && canalStretch.ToNode.WaterLevel.Value > canalStretchResult.CriticalWaterLevel) { throw new NotImplementedException(); } // S2 flow // Regimen rapido se impone aguas arriba // TODO el simbolo <= debe ser mejorado else if (canalStretch.FromNode.WaterLevel.HasValue && canalStretch.FromNode.WaterLevel.Value <= canalStretchResult.CriticalWaterLevel && canalStretch.FromNode.WaterLevel.Value > canalStretchResult.NormalWaterLevel) { options.InitialX = GetAbsoluteInitialLength(CanalStretches, canalStretch) + 0.0; options.InitialWaterLevel = canalStretch.FromNode.WaterLevel.Value - Sensibility /* Salvando numéricamente por la derecha el problema */; options.BackwardsAnalysis = false; options.ExecuteAnalysis = true; } } // H flow else { if (canalStretch.FromNode.WaterLevel.HasValue) { options.InitialX = GetAbsoluteInitialLength(CanalStretches, canalStretch) + 0.0; options.InitialWaterLevel = canalStretch.FromNode.WaterLevel.Value; options.BackwardsAnalysis = false; options.ExecuteAnalysis = true; } } if (options.ExecuteAnalysis) { double x = options.InitialX; double waterLevel = options.BackwardsAnalysis ? options.FinalWaterLevel : options.InitialWaterLevel; int steps = options.AnalysisSteps; solver.Interval = canalStretch.Length / steps; solver.Equation = canalStretch.FlowEquation(); if (options.HydraulicJumpOccurs && canalStretch.FromNode.WaterLevel.HasValue && canalStretch.ToNode.WaterLevel.HasValue) { List <CanalPointResult> backwardsAnalysisResult = new List <CanalPointResult>(); List <CanalPointResult> conjugateWaterLevelResult = new List <CanalPointResult>(); List <CanalPointResult> frontAnalysisResult = new List <CanalPointResult>(); double x2 = options.InitialX + canalStretch.Length; waterLevel = options.FinalWaterLevel; for (int i = 1; i <= steps; i++) { waterLevel = solver.SolveBackwards(x2, waterLevel); x2 = x2 - solver.Interval; backwardsAnalysisResult.Add(new CanalPointResult(x2, waterLevel)); } waterLevel = options.InitialWaterLevel; while (waterLevel < canalStretchResult.CriticalWaterLevel - Sensibility) { waterLevel = solver.Solve(x, waterLevel); x = x + solver.Interval; conjugateWaterLevelResult.Add(new CanalPointResult(x, canalStretch.GetHydraulicJumpDownstreamDepth(waterLevel))); frontAnalysisResult.Add(new CanalPointResult(x, waterLevel)); } Func <double, double> conjugatedEquation = GetHydraulicJumpEquation(backwardsAnalysisResult, conjugateWaterLevelResult); BisectionMethod findHydraulicJump = new BisectionMethod(conjugatedEquation, options.InitialX + Sensibility, conjugateWaterLevelResult.OrderByDescending(wl => wl.X).First().X); double hydraulicJumpX = findHydraulicJump.Solve(0.01); // Found result, otherwise it could be "desagüe anegado" if (hydraulicJumpX < double.MaxValue) { result.AddCanalPointResult(canalStretch.Id, options.InitialX, options.InitialWaterLevel); result.AddRangeCanalPointResult(canalStretch.Id, frontAnalysisResult.Where(ar => ar.X < hydraulicJumpX).ToList()); result.AddRangeCanalPointResult(canalStretch.Id, backwardsAnalysisResult.Where(ar => ar.X >= hydraulicJumpX).ToList()); } } else if (options.BackwardsAnalysis) { result.AddCanalPointResult(canalStretch.Id, x, waterLevel); for (int i = 1; i <= steps; i++) { waterLevel = solver.SolveBackwards(x, waterLevel); x = x - solver.Interval; result.AddCanalPointResult(canalStretch.Id, x, waterLevel); } canalStretch.FromNode.WaterLevel = waterLevel; } else { result.AddCanalPointResult(canalStretch.Id, x, waterLevel); // Regimen lento se impone aguas abajo // Regimen rapido se impone aguas arriba for (int i = 1; i <= steps; i++) { waterLevel = solver.Solve(x, waterLevel); x = x + solver.Interval; result.AddCanalPointResult(canalStretch.Id, x, waterLevel); } canalStretch.ToNode.WaterLevel = waterLevel; } } } return(result); }
public CanalData(ICanal canal, CanalSimulationResult canalResult) { Canal = canal; CanalResult = canalResult; }