using System; using System.Collections.Generic; using System.Linq; namespace HydraulicSimulator.Models { /// /// Rama (elementos en serie) /// public class Branch { public string N1 { get; set; } public string N2 { get; set; } public List Elements { get; set; } public string Name { get; set; } public double Q { get; set; } = 0.0; // caudal actual (signo n1->n2) public Branch(string n1, string n2, List elements, string name = "") { N1 = n1; N2 = n2; Elements = new List(elements); Name = string.IsNullOrEmpty(name) ? $"{n1}->{n2}" : name; } public double Dp(double q, Fluid fluid) { return Elements.Sum(e => e.Dp(q, fluid)); } public double DdpDq(double q, Fluid fluid) { return Elements.Sum(e => e.DdpDq(q, fluid)); } /// /// Resuelve ΔP(q) = dpTarget por Newton 1D con amortiguación. /// public double SolveFlowGivenDp(double dpTarget, Fluid fluid) { var q = Q; var qMax = 1.0; // m³/s máximo razonable for (int i = 0; i < 50; i++) // más iteraciones { var f = Dp(q, fluid) - dpTarget; var df = DdpDq(q, fluid); // Verificar división por cero if (Math.Abs(df) < 1e-20) df = 1e-10; var step = f / df; // Limitar el paso para estabilidad var maxStep = Math.Min(0.1, Math.Abs(q) * 0.5 + 0.01); if (Math.Abs(step) > maxStep) step = Math.Sign(step) * maxStep; var qNew = q - step; // Limitar caudal dentro de rango razonable qNew = Math.Max(-qMax, Math.Min(qMax, qNew)); // Amortiguación más conservadora var relax = i < 10 ? 0.3 : 0.1; q = (1 - relax) * q + relax * qNew; // Criterio de convergencia más estricto if (Math.Abs(f) < 1e-1) // Pa break; // Debug: evitar divergencia extrema if (Math.Abs(q) > qMax) q = Math.Sign(q) * qMax * 0.1; } Q = q; return q; } } }