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;
}
}
}