using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Windows;
using CtrEditor.HydraulicSimulator.Python;
using CtrEditor.HydraulicSimulator.TSNet.Components;
using HydraulicSimulator.Models;
using CtrEditor.ObjetosSim;
namespace CtrEditor.HydraulicSimulator.TSNet
{
///
/// Gestor de simulaciones TSNet que reemplaza o complementa al HydraulicSimulationManager
///
public class TSNetSimulationManager : IDisposable
{
#region Properties and Fields
///
/// Red hidráulica actual
///
public HydraulicNetwork Network { get; private set; }
///
/// Lista de objetos hidráulicos registrados
///
public List HydraulicObjects { get; private set; }
///
/// Directorio de trabajo para archivos INP y resultados
///
public string WorkingDirectory { get; set; }
///
/// Ruta del archivo INP actual
///
public string CurrentInpFile { get; private set; }
///
/// Configuración de la simulación transitoria
///
public TSNetConfiguration Configuration { get; set; }
///
/// Resultado de la última simulación
///
public TSNetResult LastResult { get; private set; }
///
/// Indica si la simulación está ejecutándose
///
public bool IsRunning { get; private set; }
///
/// Indica si la red necesita ser reconstruida
///
public bool NetworkNeedsRebuild { get; set; } = true;
///
/// Evento disparado cuando se completa una simulación
///
public event EventHandler SimulationCompleted;
///
/// Mapeo de objetos por ID
///
private Dictionary _objectMapping;
///
/// Adaptadores para tanques registrados
///
private Dictionary _tankAdapters;
///
/// Adaptadores para bombas registradas
///
private Dictionary _pumpAdapters;
///
/// Adaptadores para tuberías registradas
///
private Dictionary _pipeAdapters;
#endregion
#region Constructor
public TSNetSimulationManager()
{
Network = new HydraulicNetwork();
HydraulicObjects = new List();
_objectMapping = new Dictionary();
// Inicializar adaptadores
_tankAdapters = new Dictionary();
_pumpAdapters = new Dictionary();
_pipeAdapters = new Dictionary();
// Configuración por defecto
Configuration = new TSNetConfiguration
{
Duration = 1.0, // 1 segundo para ver transferencia sin extremos
TimeStep = 0.01, // 0.01 segundos para precisión
OutputDirectory = Path.Combine(Path.GetTempPath(), "TSNet")
};
WorkingDirectory = Configuration.OutputDirectory;
EnsureWorkingDirectory();
// Inicializar Python si no está ya
if (!PythonInterop.Initialize())
{
Debug.WriteLine("Warning: No se pudo inicializar Python para TSNet");
}
}
#endregion
#region Network Management
///
/// Registra un objeto hidráulico en el sistema TSNet
/// IMPORTANTE: NO se realizan cálculos locales - todo se delega a TSNet
///
public void RegisterHydraulicObject(osBase hydraulicObject)
{
if (hydraulicObject == null) return;
// Asegurar que el objeto tenga un Id válido
hydraulicObject.CheckData();
if (!HydraulicObjects.Contains(hydraulicObject))
{
HydraulicObjects.Add(hydraulicObject);
var objectId = hydraulicObject.Id.Value.ToString();
_objectMapping[objectId] = hydraulicObject;
// Crear adaptador específico según el tipo de objeto
CreateAdapterForObject(hydraulicObject);
Debug.WriteLine($"TSNet: Objeto hidráulico registrado: {hydraulicObject.Nombre} (ID: {objectId})");
}
}
///
/// Crea el adaptador apropiado para el objeto hidráulico
///
private void CreateAdapterForObject(osBase hydraulicObject)
{
var objectId = hydraulicObject.Id.Value.ToString();
switch (hydraulicObject)
{
case osHydTank tank:
try
{
var tankAdapter = new TSNetTankAdapter(tank);
tankAdapter.CaptureConfigurationForSimulation(); // Capturar configuración inmediatamente
_tankAdapters[objectId] = tankAdapter;
Debug.WriteLine($"TSNet: Adaptador de tanque creado para {tank.Nombre}");
}
catch (Exception ex)
{
Debug.WriteLine($"TSNet ERROR: Error creando adaptador de tanque para {tank.Nombre}: {ex.Message}");
}
break;
case osHydPump pump:
try
{
var pumpAdapter = new TSNetPumpAdapter(pump);
pumpAdapter.CaptureConfigurationForSimulation(); // Capturar configuración inmediatamente
_pumpAdapters[objectId] = pumpAdapter;
Debug.WriteLine($"TSNet: Adaptador de bomba creado para {pump.Nombre}");
}
catch (Exception ex)
{
Debug.WriteLine($"TSNet ERROR: Error creando adaptador de bomba para {pump.Nombre}: {ex.Message}");
}
break;
case osHydPipe pipe:
try
{
var pipeAdapter = new TSNetPipeAdapter(pipe);
pipeAdapter.CaptureConfigurationForSimulation(); // Capturar configuración inmediatamente
_pipeAdapters[objectId] = pipeAdapter;
Debug.WriteLine($"TSNet: Adaptador de tubería creado para {pipe.Nombre}");
}
catch (Exception ex)
{
Debug.WriteLine($"TSNet ERROR: Error creando adaptador de tubería para {pipe.Nombre}: {ex.Message}");
}
break;
default:
Debug.WriteLine($"TSNet: Tipo de objeto no soportado: {hydraulicObject.GetType().Name}");
break;
}
}
///
/// Desregistra un objeto hidráulico y su adaptador
///
public void UnregisterHydraulicObject(osBase hydraulicObject)
{
if (hydraulicObject == null) return;
var objectId = hydraulicObject.Id.Value.ToString();
HydraulicObjects.Remove(hydraulicObject);
_objectMapping.Remove(objectId);
// Remover adaptadores específicos
_tankAdapters.Remove(objectId);
_pumpAdapters.Remove(objectId);
_pipeAdapters.Remove(objectId);
Debug.WriteLine($"TSNet: Objeto hidráulico desregistrado: {hydraulicObject.Nombre} (ID: {objectId})");
}
///
/// Reconstruye la red hidráulica a partir de los objetos registrados
///
public void RebuildNetwork()
{
try
{
Network = new HydraulicNetwork();
var hydraulicComponents = HydraulicObjects.OfType().ToList();
// Primera pasada: Agregar TODOS los nodos
Debug.WriteLine("TSNet: Primera pasada - agregando todos los nodos...");
foreach (var component in hydraulicComponents)
{
try
{
var nodes = component.GetHydraulicNodes();
foreach (var nodeDefinition in nodes)
{
if (nodeDefinition.IsFixedPressure)
{
Network.AddNode(nodeDefinition.Name, nodeDefinition.Pressure);
}
else
{
Network.AddNode(nodeDefinition.Name);
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error agregando nodos del componente {component}: {ex.Message}");
}
}
Debug.WriteLine($"TSNet: Nodos agregados - Total: {Network.Nodes.Count}");
Debug.WriteLine($"TSNet: Nodos disponibles: {string.Join(", ", Network.Nodes.Keys)}");
// Segunda pasada: Agregar TODOS los elementos
Debug.WriteLine("TSNet: Segunda pasada - agregando todos los elementos...");
foreach (var component in hydraulicComponents)
{
try
{
var elements = component.GetHydraulicElements();
foreach (var elementDefinition in elements)
{
try
{
// Verificar que los nodos existan antes de agregar el elemento
if (Network.Nodes.ContainsKey(elementDefinition.FromNode) &&
Network.Nodes.ContainsKey(elementDefinition.ToNode))
{
Network.AddElement(elementDefinition.Element,
elementDefinition.FromNode,
elementDefinition.ToNode,
elementDefinition.Name);
Debug.WriteLine($"Rama agregada: {elementDefinition.Name} ({elementDefinition.FromNode} -> {elementDefinition.ToNode})");
}
else
{
Debug.WriteLine($"ERROR: Nodo '{elementDefinition.FromNode}' o '{elementDefinition.ToNode}' no existe. " +
$"Nodos disponibles: {string.Join(", ", Network.Nodes.Keys)}");
}
}
catch (Exception elementEx)
{
Debug.WriteLine($"Error agregando elemento {elementDefinition.Name}: {elementEx.Message}");
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error obteniendo elementos del componente {component}: {ex.Message}");
}
}
Debug.WriteLine($"TSNet: Red reconstruida - {Network.Nodes.Count} nodos, {Network.Branches.Count} ramas");
}
catch (Exception ex)
{
Debug.WriteLine($"Error reconstruyendo red TSNet: {ex.Message}");
}
}
///
/// Obtiene el adaptador de tanque por ID
///
public TSNetTankAdapter GetTankAdapter(string objectId)
{
return _tankAdapters.TryGetValue(objectId, out var adapter) ? adapter : null;
}
///
/// Obtiene el adaptador de tanque por nombre de nodo de la red hidráulica
///
public TSNetTankAdapter GetTankAdapterByNodeName(string nodeName)
{
foreach (var adapter in _tankAdapters.Values)
{
if (adapter?.Tank?.Nombre == nodeName)
{
return adapter;
}
}
return null;
}
///
/// Obtiene el adaptador de bomba por ID
///
public TSNetPumpAdapter GetPumpAdapter(string objectId)
{
return _pumpAdapters.TryGetValue(objectId, out var adapter) ? adapter : null;
}
///
/// Obtiene el adaptador de tubería por ID
///
public TSNetPipeAdapter GetPipeAdapter(string objectId)
{
return _pipeAdapters.TryGetValue(objectId, out var adapter) ? adapter : null;
}
///
/// Resetea todos los valores calculados en todos los objetos
/// IMPORTANTE: Solo resetea valores calculados por TSNet, NO configuraciones del usuario
///
public void ResetAllCalculatedValues()
{
// Resetear adaptadores de tanques
foreach (var tankAdapter in _tankAdapters.Values)
{
tankAdapter.ResetCalculatedValues();
}
// Resetear adaptadores de bombas
foreach (var pumpAdapter in _pumpAdapters.Values)
{
pumpAdapter.ResetCalculatedValues();
}
// Resetear adaptadores de tuberías
foreach (var pipeAdapter in _pipeAdapters.Values)
{
pipeAdapter.ResetCalculatedValues();
}
Debug.WriteLine("TSNet: Todos los valores calculados han sido reseteados");
}
///
/// Captura la configuración de TODOS los adaptadores al INICIO de simulación
/// Las configuraciones quedan CONGELADAS hasta que se detenga y reinicie la simulación
///
private void CaptureAllConfigurations()
{
Debug.WriteLine("TSNet: Capturando configuraciones de todos los objetos...");
// Capturar configuración de tanques
foreach (var tankAdapter in _tankAdapters.Values)
{
tankAdapter.CaptureConfigurationForSimulation();
}
// Capturar configuración de bombas
foreach (var pumpAdapter in _pumpAdapters.Values)
{
pumpAdapter.CaptureConfigurationForSimulation();
}
// Capturar configuración de tuberías
foreach (var pipeAdapter in _pipeAdapters.Values)
{
pipeAdapter.CaptureConfigurationForSimulation();
}
Debug.WriteLine($"TSNet: Configuraciones capturadas - Tanques: {_tankAdapters.Count}, Bombas: {_pumpAdapters.Count}, Tuberías: {_pipeAdapters.Count}");
}
///
/// Aplica los resultados de TSNet a todos los objetos registrados
/// IMPORTANTE: Esta es la ÚNICA forma de actualizar propiedades calculadas
///
public void ApplyTSNetResults(Dictionary> allResults)
{
if (allResults == null) return;
try
{
// Aplicar resultados a tanques
foreach (var kvp in _tankAdapters)
{
var objectId = kvp.Key;
var adapter = kvp.Value;
// Crear diccionarios vacíos para flows y pressures si no existen
var flows = new Dictionary();
var pressures = new Dictionary();
adapter.ApplyTSNetResults(flows, pressures);
}
// Aplicar resultados a bombas
foreach (var kvp in _pumpAdapters)
{
var objectId = kvp.Key;
var adapter = kvp.Value;
var flows = new Dictionary();
var pressures = new Dictionary();
adapter.ApplyTSNetResults(flows, pressures);
}
// Aplicar resultados a tuberías
foreach (var kvp in _pipeAdapters)
{
var objectId = kvp.Key;
var adapter = kvp.Value;
var flows = new Dictionary();
var pressures = new Dictionary();
adapter.ApplyTSNetResults(flows, pressures);
}
Debug.WriteLine($"TSNet: Resultados aplicados a {_tankAdapters.Count} tanques, {_pumpAdapters.Count} bombas, {_pipeAdapters.Count} tuberías");
}
catch (Exception ex)
{
Debug.WriteLine($"Error aplicando resultados TSNet: {ex.Message}");
throw;
}
}
///
/// Valida la configuración de todos los adaptadores
///
public List ValidateAllConfigurations()
{
var allErrors = new List();
// Verificar que los diccionarios estén inicializados
if (_tankAdapters == null || _pumpAdapters == null || _pipeAdapters == null)
{
allErrors.Add("Error interno: Adaptadores no inicializados correctamente");
return allErrors;
}
// Validar tanques
foreach (var adapter in _tankAdapters.Values)
{
if (adapter != null)
{
var errors = adapter.ValidateConfiguration();
if (errors != null)
allErrors.AddRange(errors);
}
else
{
allErrors.Add("Error interno: Adaptador de tanque nulo detectado");
}
}
// Validar bombas
foreach (var adapter in _pumpAdapters.Values)
{
if (adapter != null)
{
var errors = adapter.ValidateConfiguration();
if (errors != null)
allErrors.AddRange(errors);
}
else
{
allErrors.Add("Error interno: Adaptador de bomba nulo detectado");
}
}
// Validar tuberías
foreach (var adapter in _pipeAdapters.Values)
{
if (adapter != null)
{
var errors = adapter.ValidateConfiguration();
if (errors != null)
allErrors.AddRange(errors);
}
else
{
allErrors.Add("Error interno: Adaptador de tubería nulo detectado");
}
}
if (allErrors.Count > 0)
{
Debug.WriteLine($"TSNet: Se encontraron {allErrors.Count} errores de configuración");
foreach (var error in allErrors)
{
Debug.WriteLine($" - {error}");
}
}
return allErrors;
}
#endregion
#region INP File Generation
///
/// Genera el archivo INP para TSNet
///
public async Task GenerateINPFileAsync()
{
try
{
var inpPath = Path.Combine(WorkingDirectory, $"network_{DateTime.Now:yyyyMMdd_HHmmss}.inp");
var inpGenerator = new TSNetINPGenerator(Network, Configuration, this);
await inpGenerator.GenerateAsync(inpPath);
CurrentInpFile = inpPath;
Debug.WriteLine($"TSNet: Archivo INP generado: {inpPath}");
return inpPath;
}
catch (Exception ex)
{
Debug.WriteLine($"Error generando archivo INP: {ex.Message}");
throw;
}
}
#endregion
#region Simulation
///
/// Ejecuta una simulación TSNet asíncrona
///
public async Task RunSimulationAsync()
{
try
{
if (IsRunning)
{
Debug.WriteLine("TSNet: Simulación ya en ejecución");
return LastResult;
}
IsRunning = true;
// PASO 1: CAPTURAR configuración de todos los adaptadores al INICIO
CaptureAllConfigurations();
// Reconstruir red si es necesario
RebuildNetwork();
// Generar archivo INP
var inpFile = await GenerateINPFileAsync();
Debug.WriteLine($"TSNet: Archivo INP generado: {inpFile}");
// Ejecutar simulación TSNet
var result = await PythonInterop.RunTSNetSimulationAsync(inpFile, Configuration.OutputDirectory);
// LOG: Registrar resultado detallado para diagnóstico de división por cero
Debug.WriteLine($"TSNet: Resultado de simulación - Success: {result.Success}");
Debug.WriteLine($"TSNet: Output: {result.Output}");
if (!string.IsNullOrEmpty(result.Error))
{
Debug.WriteLine($"TSNet: Error: {result.Error}");
}
// Procesar resultados
LastResult = new TSNetResult
{
Success = result.Success,
Message = result.Success ? "Simulación completada" : result.Error,
OutputDirectory = Configuration.OutputDirectory,
PythonOutput = result.Output,
PythonError = result.Error
};
// Aplicar resultados a objetos hidráulicos
if (LastResult.Success)
{
await ApplyResultsToObjectsAsync();
}
// Disparar evento
SimulationCompleted?.Invoke(this, LastResult);
return LastResult;
}
catch (Exception ex)
{
LastResult = new TSNetResult
{
Success = false,
Message = $"Error en simulación: {ex.Message}"
};
Debug.WriteLine($"Error en simulación TSNet: {ex.Message}");
return LastResult;
}
finally
{
IsRunning = false;
}
}
///
/// Ejecuta una simulación continua (para tiempo real)
///
public async Task StartContinuousSimulationAsync(int intervalMs = 1000)
{
// TODO: Implementar simulación continua
// Esta será la clave para integración en tiempo real
await Task.Delay(intervalMs);
}
#endregion
#region Results Processing
///
/// Aplica los resultados de TSNet a los objetos hidráulicos
///
private async Task ApplyResultsToObjectsAsync()
{
try
{
Debug.WriteLine("TSNet: Leyendo resultados de simulación...");
// Leer archivo de resultados JSON generado por Python
var resultsFilePath = Path.Combine(Path.GetTempPath(), "TSNet", "tsnet_results.json");
var flows = new Dictionary();
var pressures = new Dictionary();
var tankLevels = new Dictionary(); // Niveles específicos de tanques
if (File.Exists(resultsFilePath))
{
try
{
var jsonContent = await File.ReadAllTextAsync(resultsFilePath);
var resultsData = System.Text.Json.JsonSerializer.Deserialize>(jsonContent);
// Extraer presiones de nodos
if (resultsData.ContainsKey("nodes"))
{
var nodesJson = resultsData["nodes"].ToString();
var nodeResults = System.Text.Json.JsonSerializer.Deserialize>(nodesJson);
foreach (var kvp in nodeResults)
{
pressures[kvp.Key] = kvp.Value;
Debug.WriteLine($"TSNet: Nodo {kvp.Key} = {kvp.Value:F3} m");
}
}
// Extraer NIVELES ESPECÍFICOS DE TANQUES (calculados por TSNet)
if (resultsData.ContainsKey("tank_levels"))
{
var tankLevelsJson = resultsData["tank_levels"].ToString();
var tankResults = System.Text.Json.JsonSerializer.Deserialize>(tankLevelsJson);
foreach (var kvp in tankResults)
{
tankLevels[kvp.Key] = kvp.Value;
Debug.WriteLine($"TSNet: TANQUE {kvp.Key} NIVEL = {kvp.Value:F3} m (DINÁMICO CALCULADO)");
}
}
// Extraer flujos de tuberías
if (resultsData.ContainsKey("pipes"))
{
var pipesJson = resultsData["pipes"].ToString();
var pipeResults = System.Text.Json.JsonSerializer.Deserialize>(pipesJson);
foreach (var kvp in pipeResults)
{
flows[kvp.Key] = kvp.Value;
Debug.WriteLine($"TSNet: Tubería {kvp.Key} = {kvp.Value:F6} m³/s");
}
}
Debug.WriteLine($"TSNet: Cargados {pressures.Count} presiones, {tankLevels.Count} niveles de tanques y {flows.Count} flujos");
}
catch (Exception ex)
{
Debug.WriteLine($"TSNet: Error leyendo archivo de resultados: {ex.Message}");
// Continuar con diccionarios vacíos
}
}
else
{
Debug.WriteLine($"TSNet: Archivo de resultados no encontrado: {resultsFilePath}");
// Continuar con diccionarios vacíos
}
// Debug: Verificar objetos hidráulicos disponibles
Debug.WriteLine($"TSNet: Objetos hidráulicos registrados: {HydraulicObjects.Count}");
foreach (var obj in HydraulicObjects)
{
Debug.WriteLine($"TSNet: Objeto disponible: {obj.GetType().Name} - {obj}");
}
// CORRECCIÓN THREADING: Ejecutar en UI thread para evitar errores de cross-thread
await Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
int objectsProcessed = 0;
foreach (var obj in HydraulicObjects)
{
if (obj is IHydraulicComponent hydraulicComponent)
{
try
{
// Aplicar resultados hidráulicos estándar (flujos y presiones)
hydraulicComponent.ApplyHydraulicResults(flows, pressures);
// APLICAR NIVELES ESPECÍFICOS DE TANQUES CALCULADOS POR TSNET
if (obj is osHydTank tank)
{
// Buscar en tankLevels usando el nombre original del tanque
var originalName = tank.Nombre;
// Sanitizar nombre (lógica simple inline)
var sanitizedName = originalName?.Replace(" ", "_") ?? "UnknownNode";
if (tankLevels.ContainsKey(originalName))
{
var calculatedLevel = tankLevels[originalName];
Debug.WriteLine($"TSNet: Aplicando NIVEL DINÁMICO calculado a tanque {originalName}: {calculatedLevel:F3} m");
tank.CurrentLevelM = calculatedLevel;
Debug.WriteLine($"TSNet: Tanque {originalName} actualizado - Nivel: {tank.CurrentLevelM:F3}m, Fill%: {tank.FillPercentage:F1}%");
}
else if (tankLevels.ContainsKey(sanitizedName))
{
var calculatedLevel = tankLevels[sanitizedName];
Debug.WriteLine($"TSNet: Aplicando NIVEL DINÁMICO calculado a tanque {originalName} (usando nombre sanitizado {sanitizedName}): {calculatedLevel:F3} m");
tank.CurrentLevelM = calculatedLevel;
Debug.WriteLine($"TSNet: Tanque {originalName} actualizado - Nivel: {tank.CurrentLevelM:F3}m, Fill%: {tank.FillPercentage:F1}%");
}
else
{
Debug.WriteLine($"TSNet: WARNING - No se encontró nivel calculado para tanque '{originalName}' ni '{sanitizedName}' en tankLevels");
Debug.WriteLine($"TSNet: Claves disponibles en tankLevels: {string.Join(", ", tankLevels.Keys)}");
}
}
objectsProcessed++;
Debug.WriteLine($"TSNet: Resultados aplicados a {obj}");
}
catch (Exception ex)
{
Debug.WriteLine($"Error aplicando resultados a {obj}: {ex.Message}");
}
}
else
{
Debug.WriteLine($"TSNet: Objeto {obj} no es IHydraulicComponent");
}
}
Debug.WriteLine($"TSNet: Procesados {objectsProcessed} objetos de {HydraulicObjects.Count} totales");
}), System.Windows.Threading.DispatcherPriority.Background);
Debug.WriteLine("TSNet: Resultados aplicados a objetos hidráulicos");
}
catch (Exception ex)
{
Debug.WriteLine($"Error aplicando resultados: {ex.Message}");
}
}
#endregion
#region Private Methods
///
/// Procesa un componente hidráulico para crear nodos y elementos
///
private void ProcessHydraulicComponent(IHydraulicComponent component)
{
try
{
// Obtener nodos del componente
var nodes = component.GetHydraulicNodes();
foreach (var nodeDefinition in nodes)
{
if (nodeDefinition.IsFixedPressure)
{
Network.AddNode(nodeDefinition.Name, nodeDefinition.Pressure);
}
else
{
Network.AddNode(nodeDefinition.Name);
}
}
// Obtener elementos del componente
var elements = component.GetHydraulicElements();
foreach (var elementDefinition in elements)
{
try
{
// Verificar que los nodos existan antes de agregar el elemento
if (Network.Nodes.ContainsKey(elementDefinition.FromNode) &&
Network.Nodes.ContainsKey(elementDefinition.ToNode))
{
Network.AddElement(elementDefinition.Element,
elementDefinition.FromNode,
elementDefinition.ToNode,
elementDefinition.Name);
Debug.WriteLine($"Rama agregada: {elementDefinition.Name} ({elementDefinition.FromNode} -> {elementDefinition.ToNode})");
}
else
{
Debug.WriteLine($"ERROR: Nodo '{elementDefinition.FromNode}' o '{elementDefinition.ToNode}' no existe. " +
$"Nodos disponibles: {string.Join(", ", Network.Nodes.Keys)}");
}
}
catch (Exception elementEx)
{
Debug.WriteLine($"Error agregando elemento {elementDefinition.Name}: {elementEx.Message}");
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error procesando componente hidráulico {component}: {ex.Message}");
}
}
///
/// Asegura que el directorio de trabajo existe
///
private void EnsureWorkingDirectory()
{
try
{
if (!Directory.Exists(WorkingDirectory))
{
Directory.CreateDirectory(WorkingDirectory);
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error creando directorio de trabajo: {ex.Message}");
}
}
#endregion
#region Additional Methods for Compatibility
///
/// Reinicia el simulador hidráulico (equivalente a Reset del HydraulicSimulationManager)
///
public void Reset()
{
ResetAllCalculatedValues();
Debug.WriteLine("TSNet: Simulador reiniciado");
}
///
/// Obtiene estadísticas de la simulación
///
public string GetSimulationStats()
{
return $"TSNet - Objetos: {HydraulicObjects.Count}, Tanques: {_tankAdapters.Count}, Bombas: {_pumpAdapters.Count}, Tuberías: {_pipeAdapters.Count}";
}
///
/// Propiedad para habilitar/deshabilitar la simulación hidráulica
///
public bool IsHydraulicSimulationEnabled { get; set; } = true;
///
/// Limpia todos los objetos hidráulicos
///
public void ClearHydraulicObjects()
{
HydraulicObjects.Clear();
_objectMapping.Clear();
_tankAdapters.Clear();
_pumpAdapters.Clear();
_pipeAdapters.Clear();
Network = new HydraulicNetwork();
Debug.WriteLine("TSNet: Todos los objetos hidráulicos limpiados");
}
///
/// Invalida la red para forzar reconstrucción
///
public void InvalidateNetwork()
{
NetworkNeedsRebuild = true;
Debug.WriteLine("TSNet: Red invalidada y marcada para reconstrucción");
}
#endregion
#region IDisposable
public void Dispose()
{
try
{
HydraulicObjects?.Clear();
_objectMapping?.Clear();
// Limpiar archivos temporales si es necesario
// Note: No finalizamos Python aquí porque puede ser usado por otros
}
catch (Exception ex)
{
Debug.WriteLine($"Error en dispose de TSNetSimulationManager: {ex.Message}");
}
}
#endregion
}
#region Supporting Classes
///
/// Configuración para simulaciones TSNet
///
public class TSNetConfiguration
{
///
/// Duración de la simulación en segundos
///
public double Duration { get; set; } = 10.0;
///
/// Paso de tiempo en segundos
///
public double TimeStep { get; set; } = 0.01;
///
/// Directorio de salida para resultados
///
public string OutputDirectory { get; set; }
///
/// Configuración de válvulas/bombas
///
public Dictionary DeviceSettings { get; set; } = new Dictionary();
}
///
/// Resultado de una simulación TSNet
///
public class TSNetResult
{
public bool Success { get; set; }
public string Message { get; set; }
public string OutputDirectory { get; set; }
public string PythonOutput { get; set; }
public string PythonError { get; set; }
public DateTime Timestamp { get; set; } = DateTime.Now;
}
#endregion
}