CtrEditor/Documentation/Hidraulic/FluidSystemEnhancements.md

13 KiB

🔧 Mejoras Necesarias al Sistema de Fluidos - CtrEditor

🎯 Problemas Identificados

1. Tuberías (osHydPipe) - Falta Información de Fluidos

Problema: Las tuberías no muestran:

  • Tipo de fluido que las atraviesa
  • Propiedades del fluido (temperatura, Brix, viscosidad)
  • Flujo en unidades apropiadas (L/min)
  • Color visual basado en el tipo de fluido

Estado Actual:

[Category("📊 Estado")]
[Description("Flujo actual a través de la tubería en m³/s")]
public double CurrentFlow { get; set; }

[Category("📊 Estado")]  
[Description("Pérdida de presión en la tubería en Pa")]
public double PressureDrop { get; set; }

Propiedades Faltantes:

// Propiedades de fluido que deben agregarse
public FluidProperties CurrentFluid { get; set; }
public string CurrentFluidDescription { get; }
public double CurrentFlowLMin { get; } // Flujo en L/min
public SolidColorBrush FluidColor { get; } // Color basado en el fluido

2. Bomba (osHydPump) - Sin Información del Fluido Bombeado

Problema: La bomba no muestra:

  • Tipo de fluido que está bombeando
  • Propiedades del fluido actual
  • Efecto de la viscosidad en el rendimiento
  • Color visual según el fluido

Propiedades Faltantes:

public FluidProperties CurrentFluid { get; set; }
public string CurrentFluidDescription { get; }
public double ViscosityEffect { get; } // Factor de eficiencia por viscosidad
public double EffectiveFlow { get; } // Flujo ajustado por viscosidad

3. Tanques (osHydTank) - Gestión Inadecuada de Fluidos Duales

Problema:

  • Los niveles de fluidos primario/secundario no disminuyen proporcionalmente
  • Falta selector de tipo de flujo de salida (Primario/Secundario/Mix)
  • El volumen total no se gestiona correctamente

Funcionalidades Faltantes:

// Enum para tipo de salida
public enum TankOutputMode
{
    Primary,    // Solo fluido primario
    Secondary,  // Solo fluido secundario  
    Mixed       // Mezcla según configuración
}

public TankOutputMode OutputMode { get; set; }
public double PrimaryLevelM { get; } // Nivel específico del primario
public double SecondaryLevelM { get; } // Nivel específico del secundario

🛠️ Implementación Propuesta

Fase 1: Mejoras en osHydPipe

public partial class osHydPipe : osBase, IHydraulicComponent
{
    // Propiedades de fluido actuales
    private FluidProperties _currentFluid = new FluidProperties(FluidType.Air);
    
    [Category("🧪 Fluido Actual")]
    [DisplayName("Tipo de fluido")]
    [Description("Tipo de fluido que atraviesa la tubería")]
    [ReadOnly(true)]
    public FluidType CurrentFluidType
    {
        get => _currentFluid.Type;
        private set
        {
            if (_currentFluid.Type != value)
            {
                _currentFluid.Type = value;
                OnPropertyChanged();
                OnPropertyChanged(nameof(CurrentFluidDescription));
                OnPropertyChanged(nameof(FluidColor));
            }
        }
    }
    
    [Category("🧪 Fluido Actual")]
    [DisplayName("Descripción")]
    [Description("Descripción completa del fluido actual")]
    [ReadOnly(true)]
    public string CurrentFluidDescription => _currentFluid.Description;
    
    [Category("📊 Estado")]
    [DisplayName("Flujo (L/min)")]
    [Description("Flujo actual en litros por minuto")]
    [ReadOnly(true)]
    public double CurrentFlowLMin => CurrentFlow * 60000.0; // Conversión de m³/s a L/min
    
    [JsonIgnore]
    public SolidColorBrush FluidColor
    {
        get
        {
            var colorHex = _currentFluid.Color;
            return new SolidColorBrush((Color)ColorConverter.ConvertFromString(colorHex));
        }
    }
    
    // Método para actualizar fluido desde componente fuente
    public void UpdateFluidFromSource(FluidProperties sourceFluid)
    {
        if (sourceFluid != null)
        {
            _currentFluid = sourceFluid.Clone();
            OnPropertyChanged(nameof(CurrentFluidType));
            OnPropertyChanged(nameof(CurrentFluidDescription));
            OnPropertyChanged(nameof(FluidColor));
        }
    }
}

Fase 2: Mejoras en osHydPump

public partial class osHydPump : osBase, IHydraulicComponent
{
    private FluidProperties _currentFluid = new FluidProperties(FluidType.Air);
    
    [Category("🧪 Fluido Actual")]
    [DisplayName("Tipo de fluido")]
    [Description("Tipo de fluido que está bombeando")]
    [ReadOnly(true)]
    public FluidType CurrentFluidType => _currentFluid.Type;
    
    [Category("🧪 Fluido Actual")]
    [DisplayName("Descripción")]
    [Description("Descripción del fluido que se está bombeando")]
    [ReadOnly(true)]
    public string CurrentFluidDescription => _currentFluid.Description;
    
    [Category("📊 Estado Actual")]
    [DisplayName("Factor Viscosidad")]
    [Description("Factor de eficiencia debido a la viscosidad del fluido")]
    [ReadOnly(true)]
    public double ViscosityEffect
    {
        get
        {
            // Factor basado en viscosidad del fluido vs agua
            var waterViscosity = 0.001; // Pa·s
            var currentViscosity = _currentFluid.Viscosity;
            return Math.Max(0.1, Math.Min(1.0, waterViscosity / currentViscosity));
        }
    }
    
    [Category("📊 Estado Actual")]
    [DisplayName("Flujo Efectivo (L/min)")]
    [Description("Flujo real ajustado por viscosidad")]
    [ReadOnly(true)]
    public double EffectiveFlowLMin => CurrentFlow * 60000.0 * ViscosityEffect;
    
    // Método para actualizar fluido desde tanque de succión
    public void UpdateFluidFromSuction()
    {
        // Buscar tanque o componente conectado en la succión
        var suctionComponent = FindSuctionComponent();
        if (suctionComponent is osHydTank tank)
        {
            _currentFluid = tank.CurrentOutputFluid.Clone();
            OnPropertyChanged(nameof(CurrentFluidType));
            OnPropertyChanged(nameof(CurrentFluidDescription));
            OnPropertyChanged(nameof(ViscosityEffect));
            OnPropertyChanged(nameof(EffectiveFlowLMin));
        }
    }
}

Fase 3: Mejoras en osHydTank

public partial class osHydTank : osBase, IHydraulicComponent
{
    private TankOutputMode _outputMode = TankOutputMode.Primary;
    
    [Category("🔄 Control de Salida")]
    [DisplayName("Modo de salida")]
    [Description("Selecciona qué fluido sale del tanque")]
    public TankOutputMode OutputMode
    {
        get => _outputMode;
        set
        {
            if (SetProperty(ref _outputMode, value))
            {
                OnPropertyChanged(nameof(CurrentOutputFluid));
                OnPropertyChanged(nameof(CurrentFluidDescription));
                InvalidateHydraulicNetwork();
            }
        }
    }
    
    [Category("📊 Niveles Específicos")]
    [DisplayName("Nivel Primario (m)")]
    [Description("Nivel específico del fluido primario")]
    [ReadOnly(true)]
    public double PrimaryLevelM
    {
        get
        {
            if (CrossSectionalArea <= 0) return 0;
            return PrimaryVolumeL / 1000.0 / CrossSectionalArea;
        }
    }
    
    [Category("📊 Niveles Específicos")]
    [DisplayName("Nivel Secundario (m)")]
    [Description("Nivel específico del fluido secundario")]
    [ReadOnly(true)]
    public double SecondaryLevelM
    {
        get
        {
            if (CrossSectionalArea <= 0) return 0;
            return SecondaryVolumeL / 1000.0 / CrossSectionalArea;
        }
    }
    
    // Modificación del CurrentOutputFluid para considerar OutputMode
    [JsonIgnore]
    public override FluidProperties CurrentOutputFluid
    {
        get
        {
            return OutputMode switch
            {
                TankOutputMode.Primary => PrimaryVolumeL > 0 ? _primaryFluid.Clone() : new FluidProperties(FluidType.Air),
                TankOutputMode.Secondary => SecondaryVolumeL > 0 ? _secondaryFluid.Clone() : new FluidProperties(FluidType.Air),
                TankOutputMode.Mixed => CalculateMixedOutput(),
                _ => new FluidProperties(FluidType.Air)
            };
        }
    }
    
    private FluidProperties CalculateMixedOutput()
    {
        if (PrimaryVolumeL <= 0 && SecondaryVolumeL <= 0)
            return new FluidProperties(FluidType.Air);
            
        if (PrimaryVolumeL <= 0)
            return _secondaryFluid.Clone();
            
        if (SecondaryVolumeL <= 0)
            return _primaryFluid.Clone();
            
        // Calcular ratio de mezcla basado en volúmenes
        var totalVolume = PrimaryVolumeL + SecondaryVolumeL;
        var mixRatio = SecondaryVolumeL / totalVolume;
        
        return _primaryFluid.MixWith(_secondaryFluid, mixRatio);
    }
    
    // Método para actualizar volúmenes proporcionalmente durante el flujo
    protected override void UpdateVolumeFromFlow(double deltaTimeSec)
    {
        var flowOutLMin = OutletFlow;
        var flowInLMin = InletFlow;
        var netFlowLMin = flowInLMin - flowOutLMin;
        var deltaVolumeL = netFlowLMin * deltaTimeSec / 60.0;
        
        if (deltaVolumeL < 0) // Salida neta
        {
            var outVolumeL = Math.Abs(deltaVolumeL);
            
            // Reducir volúmenes según el modo de salida
            switch (OutputMode)
            {
                case TankOutputMode.Primary:
                    PrimaryVolumeL = Math.Max(0, PrimaryVolumeL - outVolumeL);
                    break;
                    
                case TankOutputMode.Secondary:
                    SecondaryVolumeL = Math.Max(0, SecondaryVolumeL - outVolumeL);
                    break;
                    
                case TankOutputMode.Mixed:
                    // Reducir proporcionalmente
                    var totalVol = PrimaryVolumeL + SecondaryVolumeL;
                    if (totalVol > 0)
                    {
                        var primaryRatio = PrimaryVolumeL / totalVol;
                        var secondaryRatio = SecondaryVolumeL / totalVol;
                        
                        PrimaryVolumeL = Math.Max(0, PrimaryVolumeL - (outVolumeL * primaryRatio));
                        SecondaryVolumeL = Math.Max(0, SecondaryVolumeL - (outVolumeL * secondaryRatio));
                    }
                    break;
            }
        }
        else if (deltaVolumeL > 0) // Entrada neta
        {
            // El fluido que entra se añade al primario por defecto
            // TODO: Implementar lógica para determinar tipo de fluido entrante
            PrimaryVolumeL += deltaVolumeL;
        }
        
        // Actualizar nivel total
        CurrentVolumeL = PrimaryVolumeL + SecondaryVolumeL;
        CurrentLevelM = CurrentVolumeL / 1000.0 / Math.Max(0.1, CrossSectionalArea);
    }
}

public enum TankOutputMode
{
    [Description("Solo fluido primario")]
    Primary,
    
    [Description("Solo fluido secundario")]
    Secondary,
    
    [Description("Mezcla proporcional")]
    Mixed
}

🔄 Lógica de Propagación de Fluidos

Algoritmo de Propagación:

  1. Tanques determinan el tipo de fluido que sale según OutputMode
  2. Bombas toman el fluido del componente de succión
  3. Tuberías transportan el fluido desde el componente fuente
  4. Actualización en tiempo real durante la simulación

Implementación en UpdateControl():

public override void UpdateControl(int elapsedMilliseconds)
{
    base.UpdateControl(elapsedMilliseconds);
    
    // Actualizar propiedades del fluido
    UpdateFluidProperties();
    
    // Actualizar volúmenes (solo tanques)
    if (this is osHydTank tank)
    {
        tank.UpdateVolumeFromFlow(elapsedMilliseconds / 1000.0);
    }
}

private void UpdateFluidProperties()
{
    // Lógica específica para cada tipo de componente
    if (this is osHydPump pump)
    {
        pump.UpdateFluidFromSuction();
    }
    else if (this is osHydPipe pipe)
    {
        pipe.UpdateFluidFromSource();
    }
}

📋 Plan de Implementación

Prioridad 1: Básico

  • Agregar propiedades de fluido a osHydPipe
  • Agregar propiedades de fluido a osHydPump
  • Implementar TankOutputMode en osHydTank

Prioridad 2: Funcional

  • Implementar propagación de fluidos
  • Actualización de volúmenes proporcional
  • Colores visuales según tipo de fluido

Prioridad 3: Avanzado

  • Efectos de viscosidad en bombas
  • Transitorios de mezcla
  • Optimización de rendimiento

🧪 Tests de Validación

Test 1: Propagación Básica

  • Tanque con agua → Bomba → Tubería → Tanque
  • Verificar que todas las propiedades se propaguen

Test 2: Cambio de Modo de Salida

  • Tanque con fluidos duales
  • Cambiar OutputMode y verificar propagación

Test 3: Efectos de Viscosidad

  • Comparar bombeo de agua vs jarabe
  • Verificar factor de eficiencia

Documento Técnico - Mejoras Sistema de Fluidos
Fecha: Septiembre 2025