/// <summary> /// Returns the active canal stretch from a given distance x /// </summary> /// <param name="x"></param> /// <returns></returns> public ICanalStretchModel GetCanalStretchForAbsoluteX(double x) { ICanalStretchModel canalStretch = CanalStretches.FirstOrDefault(csfirst => CanalStretches.All(cs => cs.ToNode.Id != csfirst.FromNode.Id)); double relativeDistance = x; bool found = false; while (!found && relativeDistance > 0 && canalStretch != null) { if (relativeDistance < canalStretch.Length) { found = true; } else { relativeDistance -= canalStretch.Length; var nextStretch = CanalStretches.FirstOrDefault(cs => cs.FromNode.Id == canalStretch.ToNode.Id); if (relativeDistance > 0 || nextStretch != null) { canalStretch = nextStretch; } } } return(canalStretch); }
public CanalPointResult GetCanalPointResult(double horizontalDistance) { int canalIndex = 0; bool found = false; double relativehorizontalDistance = horizontalDistance; double coordinateX = 0; while (!found && canalIndex < Canal.CanalStretches.Count) { ICanalStretchModel canalStretch = Canal.CanalStretches[canalIndex]; double relativeLengthDistance = canalStretch.Length * Math.Cos(Math.Atan(canalStretch.CanalSection.Slope)); if (relativehorizontalDistance <= relativeLengthDistance) { coordinateX += relativehorizontalDistance / Math.Cos(Math.Atan(canalStretch.CanalSection.Slope)); found = true; } else { relativehorizontalDistance -= relativeLengthDistance; coordinateX += canalStretch.Length; } } return(CanalResult?.CanalPointResults?.OrderBy(pr => Math.Abs(coordinateX - pr.X)).FirstOrDefault()); }
public void GetCanalStretchForAbsoluteXTest() { CanalEdge initialNode = new CanalEdge() { Id = "InitNode" }; CanalEdge midNode = new CanalEdge() { Id = "MidNode" }; CanalEdge endNode = new CanalEdge() { Id = "EndNode" }; CanalStretch canal = new CanalStretch("stretch1", 600, 20.32, new RectangularSection(5, 0.028, 0)); canal.FromNode = initialNode; canal.ToNode = midNode; CanalStretch canal2 = new CanalStretch("stretch2", 400, 20.32, new RectangularSection(5, 0.028, 0.004)); canal2.FromNode = midNode; canal2.ToNode = endNode; Canal globalCanal = new Canal(); globalCanal.CanalStretches = new List <ICanalStretchModel> { canal, canal2 }; globalCanal.CanelEdges = new List <ICanalEdge> { initialNode, midNode, endNode }; ICanalStretchModel result = globalCanal.GetCanalStretchForAbsoluteX(0); Assert.AreEqual(canal, result); result = globalCanal.GetCanalStretchForAbsoluteX(300); Assert.AreEqual(canal, result); result = globalCanal.GetCanalStretchForAbsoluteX(600); Assert.AreEqual(canal2, result); result = globalCanal.GetCanalStretchForAbsoluteX(900); Assert.AreEqual(canal2, result); result = globalCanal.GetCanalStretchForAbsoluteX(1000); Assert.AreEqual(canal2, result); }
private double GetAbsoluteInitialLength(List <ICanalStretchModel> canalStretches, ICanalStretchModel activeCanalStretch) { double length = 0d; ICanalStretchModel currentCanalStretch = activeCanalStretch; do { ICanalStretchModel priorCanalStretch = canalStretches.FirstOrDefault(cs => cs.ToNode.Id == currentCanalStretch.FromNode.Id); if (priorCanalStretch != null) { length += priorCanalStretch.Length; } currentCanalStretch = priorCanalStretch; } while (currentCanalStretch != null); return(length); }
public ICanalStretchModel GetCanalStretch(CanalPointResult canalPointResult) { int canalIndex = 0; double relativeCanalX = canalPointResult.X; while (canalIndex < Canal.CanalStretches.Count) { ICanalStretchModel canalStretch = Canal.CanalStretches[canalIndex]; if (relativeCanalX <= canalStretch.Length) { return(canalStretch); } else { relativeCanalX -= canalStretch.Length; } } return(null); }
/// <summary> /// Returns the canal geometry data /// </summary> /// <returns></returns> public CanalGeometryData GetCanalGeometryData(string canalStretchId) { if (canalStretchId == null) { return(new CanalGeometryData()); } ICanalStretchModel canalStretch = GetCanalStretch(canalStretchId); return(new CanalGeometryData { Length = canalStretch.Length, Flow = canalStretch.Flow, Roughness = canalStretch.CanalSection.Roughness, Slope = canalStretch.CanalSection.Slope, Id = canalStretch.Id, CriticalSlope = CanalResult?.GetCanalStretchResult(canalStretchId)?.CriticalSlope ?? 0, CriticalWaterLevel = CanalResult?.GetCanalStretchResult(canalStretchId)?.CriticalWaterLevel ?? 0, NormalWaterLevel = CanalResult?.GetCanalStretchResult(canalStretchId)?.NormalWaterLevel ?? 0, }); }
/// <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); }