public void BasicRectangularFlowTest() { CanalStretch canal = new CanalStretch("stretch1", 602, 20.32, new RectangularSection(5, 0.028, 0)); double rh = canal.CanalSection.GetHydraulicRadius(2.9); double mv = canal.CanalSection.GetManningVelocity(2.9); double fr2 = Math.Pow(canal.GetFroudeNumber(2.9), 2.0); double criticalDepth = canal.CanalSection.GetCriticalWaterLevel(20.32); double criticalSlope = canal.CanalSection.GetCriticalSlope(20.32); double flow = canal.CanalSection.GetManningFlow(canal.CanalSection.GetCriticalWaterLevel(20.32)); double normalDepth = canal.CanalSection.GetNormalWaterLevel(20.32); RungeKutta solver = new RungeKutta(1, canal.FlowEquation()); // Act double result = solver.Solve(0, 2.9); double actualRh = (5.0 * 2.9) / (5.0 + 2.0 * 2.9); Assert.IsTrue(rh - actualRh <= double.Epsilon); Assert.IsTrue(mv - 0 <= double.Epsilon); Assert.IsTrue(fr2 - 0.0690 <= 0.0001); Assert.IsTrue(result - 2.89888 <= 0.00001); Assert.IsTrue(criticalSlope > 0); Assert.IsTrue(Math.Abs(flow - 0) < Double.Epsilon); Assert.IsTrue(Math.Abs(criticalDepth - 1.1897678822813287) <= double.Epsilon); }
public void BasicRectangularFlowTest2() { CanalStretch canal = new CanalStretch("stretch1", 602, 2.5486, new RectangularSection(4, 0.014, 0.0004)); double rh = canal.CanalSection.GetHydraulicRadius(0.694); double mv = canal.CanalSection.GetManningVelocity(0.694); double fr2 = Math.Pow(canal.GetFroudeNumber(0.694), 2.0); double flow = canal.CanalSection.GetManningFlow(0.694); double criticalDepth = canal.CanalSection.GetCriticalWaterLevel(flow); double criticalSlope = canal.CanalSection.GetCriticalSlope(flow); double normalDepth = canal.CanalSection.GetNormalWaterLevel(flow); RungeKutta solver = new RungeKutta(1, canal.FlowEquation()); // Act double result = solver.Solve(0, 0.694); double actualRh = (4.0 * 0.694) / (4.0 + 2.0 * 0.694); Assert.IsTrue(rh - actualRh <= double.Epsilon); Assert.IsTrue(mv - 0.91811 <= 0.0001); Assert.IsTrue(fr2 - 1.90669 <= 0.0001); Assert.IsTrue(result - 0.694 <= 0.00001); Assert.IsTrue(criticalSlope > 0.0004); Assert.IsTrue(normalDepth > criticalDepth); Assert.IsTrue(Math.Abs(criticalDepth - 0.34593708152888353) <= double.Epsilon); }
public void BasicTest() { // Arrange Func <double, double, double> differentialEquation = (x, y) => x - y; RungeKutta solver = new RungeKutta(0.2, differentialEquation); // Act double result = solver.Solve(1, 2); // Assert double error = result - 0.2 - 2 * Math.Pow(Math.E, -0.2); // Error should be very small Assert.IsTrue(error < 0.00001); }
public Dictionary <DataPoint, DataPoint> GetPoints() { return(rungeKutta.Solve()); }
/// <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); }