예제 #1
0
        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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
 public Dictionary <DataPoint, DataPoint> GetPoints()
 {
     return(rungeKutta.Solve());
 }
예제 #5
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);
        }