Enhance TSNet simulation: optimize tank configurations, improve time settings, and extract dynamic tank levels. Update INP generator to utilize real tank data and add methods for tank adapter retrieval.
This commit is contained in:
parent
88c8eea35e
commit
baed392d90
|
@ -318,7 +318,7 @@ try:
|
||||||
|
|
||||||
# Configurar WNTR options para headloss formula
|
# Configurar WNTR options para headloss formula
|
||||||
wn.options.hydraulic.headloss = 'D-W' # Darcy-Weisbach
|
wn.options.hydraulic.headloss = 'D-W' # Darcy-Weisbach
|
||||||
wn.options.time.duration = 10.0 # 10 segundos de duración
|
wn.options.time.duration = 60.0 # 60 segundos de duración para ver transferencia real
|
||||||
wn.options.time.hydraulic_timestep = 0.01 # Paso de tiempo de 0.01 segundos
|
wn.options.time.hydraulic_timestep = 0.01 # Paso de tiempo de 0.01 segundos
|
||||||
wn.options.time.report_timestep = 0.01 # Reportar cada 0.01 segundos
|
wn.options.time.report_timestep = 0.01 # Reportar cada 0.01 segundos
|
||||||
|
|
||||||
|
@ -330,8 +330,8 @@ try:
|
||||||
print('TSNet: simulation_period inicial =', getattr(tm, 'simulation_period', 'N/A'))
|
print('TSNet: simulation_period inicial =', getattr(tm, 'simulation_period', 'N/A'))
|
||||||
print('TSNet: time_step inicial =', getattr(tm, 'time_step', 'N/A'))
|
print('TSNet: time_step inicial =', getattr(tm, 'time_step', 'N/A'))
|
||||||
|
|
||||||
# Configurar tiempo usando API oficial de TSNet
|
# Configurar tiempo usando API oficial de TSNet - TIEMPO OPTIMIZADO para co-simulación
|
||||||
simulation_time = 1.0 # 1 segundo por defecto
|
simulation_time = 1.0 # 1 segundo para ver transferencia sin extremos
|
||||||
if hasattr(tm, 'simulation_period') and tm.simulation_period > 0:
|
if hasattr(tm, 'simulation_period') and tm.simulation_period > 0:
|
||||||
simulation_time = tm.simulation_period
|
simulation_time = tm.simulation_period
|
||||||
|
|
||||||
|
@ -471,6 +471,48 @@ try:
|
||||||
tm = tsnet.simulation.Initializer(tm, t0, engine)
|
tm = tsnet.simulation.Initializer(tm, t0, engine)
|
||||||
print('TSNet: Inicialización completada')
|
print('TSNet: Inicialización completada')
|
||||||
|
|
||||||
|
# PASO 1.5: CONVERTIR TANQUES EPANET A SURGE TANKS DINÁMICOS CON CONFIGURACIONES REALISTAS
|
||||||
|
print('TSNet: Convirtiendo tanques a surge tanks dinámicos...')
|
||||||
|
tank_nodes_converted = []
|
||||||
|
|
||||||
|
# Buscar todos los tanques en el modelo
|
||||||
|
if hasattr(tm, 'tank_name_list') and tm.tank_name_list:
|
||||||
|
for tank_name in tm.tank_name_list:
|
||||||
|
try:
|
||||||
|
# Obtener información del tanque original
|
||||||
|
tank_obj = tm.get_node(tank_name)
|
||||||
|
|
||||||
|
# Usar configuraciones reales del tanque EPANET
|
||||||
|
if hasattr(tank_obj, 'init_level') and hasattr(tank_obj, 'max_level'):
|
||||||
|
# CONFIGURACIONES REALISTAS basadas en ejemplo oficial TSNet
|
||||||
|
tank_area = 5.0 # m² - área realista (ejemplo oficial usa 10 m²)
|
||||||
|
tank_height = float(tank_obj.max_level - tank_obj.min_level) if hasattr(tank_obj, 'min_level') else 5.0
|
||||||
|
water_height = float(tank_obj.init_level) if hasattr(tank_obj, 'init_level') else 1.0
|
||||||
|
|
||||||
|
# VALIDACIÓN DE UNIDADES: Asegurar que estén en metros
|
||||||
|
if tank_height < 1.0: # Si height < 1m, probablemente está en unidades incorrectas
|
||||||
|
tank_height = 5.0 # Default a 5m como en ejemplo oficial
|
||||||
|
|
||||||
|
# CRÍTICO: Asegurar que water_height esté dentro de límites válidos
|
||||||
|
if water_height > tank_height:
|
||||||
|
water_height = tank_height * 0.8 # 80% de la altura máxima
|
||||||
|
elif water_height < 0.1:
|
||||||
|
water_height = 0.5 # Mínimo 50cm
|
||||||
|
|
||||||
|
# USAR CLOSED SURGE TANKS para presurización como indica el usuario
|
||||||
|
tm.add_surge_tank(tank_name, [tank_area, tank_height, water_height], 'closed')
|
||||||
|
tank_nodes_converted.append(tank_name)
|
||||||
|
print('TSNet: Surge tank agregado: ' + tank_name + ' (área=' + str(tank_area) + 'm², altura=' + str(tank_height) + 'm, nivel_inicial=' + str(water_height) + 'm, tipo=closed)')
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print('TSNet: Error convirtiendo tanque ' + tank_name + ': ' + str(e))
|
||||||
|
pass
|
||||||
|
|
||||||
|
if tank_nodes_converted:
|
||||||
|
print('TSNet: ' + str(len(tank_nodes_converted)) + ' tanques convertidos a surge tanks dinámicos')
|
||||||
|
else:
|
||||||
|
print('TSNet: No se encontraron tanques para convertir')
|
||||||
|
|
||||||
# PASO 2: SIMULACIÓN TRANSITORIA (como en ejemplos oficiales)
|
# PASO 2: SIMULACIÓN TRANSITORIA (como en ejemplos oficiales)
|
||||||
print('TSNet: Ejecutando simulación transitoria...')
|
print('TSNet: Ejecutando simulación transitoria...')
|
||||||
results_obj = 'ctreditor_results' # nombre para guardar resultados
|
results_obj = 'ctreditor_results' # nombre para guardar resultados
|
||||||
|
@ -489,6 +531,8 @@ try:
|
||||||
|
|
||||||
# Extraer resultados de nodos usando API oficial
|
# Extraer resultados de nodos usando API oficial
|
||||||
node_results = {{}}
|
node_results = {{}}
|
||||||
|
tank_levels = {{}} # Específico para niveles de tanques
|
||||||
|
|
||||||
if hasattr(tm, 'node_name_list'):
|
if hasattr(tm, 'node_name_list'):
|
||||||
for node_name in tm.node_name_list:
|
for node_name in tm.node_name_list:
|
||||||
try:
|
try:
|
||||||
|
@ -517,6 +561,38 @@ try:
|
||||||
|
|
||||||
node_results[node_name] = final_head
|
node_results[node_name] = final_head
|
||||||
|
|
||||||
|
# EXTRACCIÓN ESPECÍFICA DE NIVELES DE TANQUES
|
||||||
|
# Los tanques en TSNet tienen propiedades especiales para niveles
|
||||||
|
if hasattr(node_obj, '_level'):
|
||||||
|
try:
|
||||||
|
if hasattr(node_obj._level, '__len__') and len(node_obj._level) > 1:
|
||||||
|
# Nivel dinámico calculado por TSNet (último valor)
|
||||||
|
tank_level = float(node_obj._level[-1])
|
||||||
|
tank_levels[node_name] = tank_level
|
||||||
|
print('TSNet: TANQUE ' + node_name + ' _level[-1]: ' + str(tank_level) + ' m (DINÁMICO)')
|
||||||
|
else:
|
||||||
|
tank_level = float(node_obj._level)
|
||||||
|
tank_levels[node_name] = tank_level
|
||||||
|
print('TSNet: TANQUE ' + node_name + ' _level: ' + str(tank_level) + ' m')
|
||||||
|
except Exception as tank_error:
|
||||||
|
print('TSNet: Error extrayendo nivel de tanque ' + node_name + ': ' + str(tank_error))
|
||||||
|
elif hasattr(node_obj, 'level'):
|
||||||
|
try:
|
||||||
|
if hasattr(node_obj.level, '__len__') and len(node_obj.level) > 1:
|
||||||
|
tank_level = float(node_obj.level[-1])
|
||||||
|
tank_levels[node_name] = tank_level
|
||||||
|
print('TSNet: TANQUE ' + node_name + ' level[-1]: ' + str(tank_level) + ' m (DINÁMICO)')
|
||||||
|
else:
|
||||||
|
tank_level = float(node_obj.level)
|
||||||
|
tank_levels[node_name] = tank_level
|
||||||
|
print('TSNet: TANQUE ' + node_name + ' level: ' + str(tank_level) + ' m')
|
||||||
|
except Exception as tank_error:
|
||||||
|
print('TSNet: Error extrayendo nivel de tanque ' + node_name + ': ' + str(tank_error))
|
||||||
|
|
||||||
|
# También verificar si es un tanque por tipo de nodo
|
||||||
|
if hasattr(node_obj, 'node_type') and 'Tank' in str(node_obj.node_type):
|
||||||
|
print('TSNet: ' + node_name + ' identificado como TANQUE por node_type')
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('TSNet: Error extrayendo resultados de nodo ' + node_name + ': ' + str(e))
|
print('TSNet: Error extrayendo resultados de nodo ' + node_name + ': ' + str(e))
|
||||||
node_results[node_name] = 0.0
|
node_results[node_name] = 0.0
|
||||||
|
@ -552,6 +628,7 @@ try:
|
||||||
results_data = {{
|
results_data = {{
|
||||||
'nodes': node_results,
|
'nodes': node_results,
|
||||||
'pipes': pipe_results,
|
'pipes': pipe_results,
|
||||||
|
'tank_levels': tank_levels, # Niveles específicos de tanques calculados por TSNet
|
||||||
'simulation_time': tm.simulation_period,
|
'simulation_time': tm.simulation_period,
|
||||||
'time_step': tm.time_step
|
'time_step': tm.time_step
|
||||||
}}
|
}}
|
||||||
|
@ -561,7 +638,7 @@ try:
|
||||||
json.dump(results_data, f, indent=2)
|
json.dump(results_data, f, indent=2)
|
||||||
|
|
||||||
print('TSNet: Resultados guardados en: ' + results_file)
|
print('TSNet: Resultados guardados en: ' + results_file)
|
||||||
print('TSNet: ' + str(len(node_results)) + ' nodos, ' + str(len(pipe_results)) + ' tuberías procesadas')
|
print('TSNet: ' + str(len(node_results)) + ' nodos, ' + str(len(pipe_results)) + ' tuberías, ' + str(len(tank_levels)) + ' tanques procesados')
|
||||||
|
|
||||||
# Guardar resultados si es necesario
|
# Guardar resultados si es necesario
|
||||||
print('Directorio de resultados: ' + r'{outputDir}')
|
print('Directorio de resultados: ' + r'{outputDir}')
|
||||||
|
|
|
@ -19,6 +19,11 @@ namespace CtrEditor.HydraulicSimulator.TSNet.Components
|
||||||
// Resultados calculados por TSNet (SOLO escritura desde TSNet)
|
// Resultados calculados por TSNet (SOLO escritura desde TSNet)
|
||||||
public TSNetTankResults Results { get; private set; }
|
public TSNetTankResults Results { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Acceso al objeto tanque hidráulico subyacente
|
||||||
|
/// </summary>
|
||||||
|
public osHydTank Tank => tank;
|
||||||
|
|
||||||
public TSNetTankAdapter(osHydTank tank)
|
public TSNetTankAdapter(osHydTank tank)
|
||||||
{
|
{
|
||||||
this.tank = tank ?? throw new ArgumentNullException(nameof(tank));
|
this.tank = tank ?? throw new ArgumentNullException(nameof(tank));
|
||||||
|
|
|
@ -17,11 +17,13 @@ namespace CtrEditor.HydraulicSimulator.TSNet
|
||||||
{
|
{
|
||||||
private readonly HydraulicNetwork _network;
|
private readonly HydraulicNetwork _network;
|
||||||
private readonly TSNetConfiguration _config;
|
private readonly TSNetConfiguration _config;
|
||||||
|
private readonly TSNetSimulationManager _simulationManager;
|
||||||
|
|
||||||
public TSNetINPGenerator(HydraulicNetwork network, TSNetConfiguration config)
|
public TSNetINPGenerator(HydraulicNetwork network, TSNetConfiguration config, TSNetSimulationManager simulationManager = null)
|
||||||
{
|
{
|
||||||
_network = network ?? throw new ArgumentNullException(nameof(network));
|
_network = network ?? throw new ArgumentNullException(nameof(network));
|
||||||
_config = config ?? throw new ArgumentNullException(nameof(config));
|
_config = config ?? throw new ArgumentNullException(nameof(config));
|
||||||
|
_simulationManager = simulationManager; // Puede ser null para compatibilidad hacia atrás
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -117,13 +119,27 @@ namespace CtrEditor.HydraulicSimulator.TSNet
|
||||||
content.AppendLine("[TANKS]");
|
content.AppendLine("[TANKS]");
|
||||||
content.AppendLine(";ID \tElevation \tInitLevel \tMinLevel \tMaxLevel \tDiameter \tMinVol \tVolCurve");
|
content.AppendLine(";ID \tElevation \tInitLevel \tMinLevel \tMaxLevel \tDiameter \tMinVol \tVolCurve");
|
||||||
|
|
||||||
// Por ahora generar tanques dummy - será expandido cuando integremos osHydTank
|
// Usar configuración real de los TSNetTankAdapter en lugar de valores dummy
|
||||||
var tankNodes = _network.Nodes.Values.Where(IsTank);
|
var tankNodes = _network.Nodes.Values.Where(IsTank);
|
||||||
foreach (var node in tankNodes)
|
foreach (var node in tankNodes)
|
||||||
{
|
{
|
||||||
var elevation = GetNodeElevation(node);
|
var elevation = GetNodeElevation(node);
|
||||||
var sanitizedName = SanitizeNodeName(node.Name);
|
var sanitizedName = SanitizeNodeName(node.Name);
|
||||||
content.AppendLine($" {sanitizedName,-15}\t{elevation.ToString("F2", CultureInfo.InvariantCulture)} \t1.0 \t0.0 \t2.0 \t1.0 \t0 \t");
|
|
||||||
|
// Buscar el adapter correspondiente en el simulation manager
|
||||||
|
var tankAdapter = _simulationManager?.GetTankAdapterByNodeName(node.Name);
|
||||||
|
|
||||||
|
if (tankAdapter?.Configuration != null)
|
||||||
|
{
|
||||||
|
// Usar configuración real del tanque
|
||||||
|
var config = tankAdapter.Configuration;
|
||||||
|
content.AppendLine($" {sanitizedName,-15}\t{elevation.ToString("F2", CultureInfo.InvariantCulture)} \t{config.InitialLevelM.ToString("F2", CultureInfo.InvariantCulture)} \t{config.MinLevelM.ToString("F2", CultureInfo.InvariantCulture)} \t{config.MaxLevelM.ToString("F2", CultureInfo.InvariantCulture)} \t{config.DiameterM.ToString("F2", CultureInfo.InvariantCulture)} \t0 \t");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Fallback a valores por defecto si no hay configuración
|
||||||
|
content.AppendLine($" {sanitizedName,-15}\t{elevation.ToString("F2", CultureInfo.InvariantCulture)} \t1.0 \t0.0 \t2.0 \t1.0 \t0 \t");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
content.AppendLine();
|
content.AppendLine();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
@ -101,8 +102,8 @@ namespace CtrEditor.HydraulicSimulator.TSNet
|
||||||
// Configuración por defecto
|
// Configuración por defecto
|
||||||
Configuration = new TSNetConfiguration
|
Configuration = new TSNetConfiguration
|
||||||
{
|
{
|
||||||
Duration = 10.0,
|
Duration = 1.0, // 1 segundo para ver transferencia sin extremos
|
||||||
TimeStep = 0.01,
|
TimeStep = 0.01, // 0.01 segundos para precisión
|
||||||
OutputDirectory = Path.Combine(Path.GetTempPath(), "TSNet")
|
OutputDirectory = Path.Combine(Path.GetTempPath(), "TSNet")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -316,6 +317,21 @@ namespace CtrEditor.HydraulicSimulator.TSNet
|
||||||
return _tankAdapters.TryGetValue(objectId, out var adapter) ? adapter : null;
|
return _tankAdapters.TryGetValue(objectId, out var adapter) ? adapter : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Obtiene el adaptador de tanque por nombre de nodo de la red hidráulica
|
||||||
|
/// </summary>
|
||||||
|
public TSNetTankAdapter GetTankAdapterByNodeName(string nodeName)
|
||||||
|
{
|
||||||
|
foreach (var adapter in _tankAdapters.Values)
|
||||||
|
{
|
||||||
|
if (adapter?.Tank?.Nombre == nodeName)
|
||||||
|
{
|
||||||
|
return adapter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Obtiene el adaptador de bomba por ID
|
/// Obtiene el adaptador de bomba por ID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -527,7 +543,7 @@ namespace CtrEditor.HydraulicSimulator.TSNet
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var inpPath = Path.Combine(WorkingDirectory, $"network_{DateTime.Now:yyyyMMdd_HHmmss}.inp");
|
var inpPath = Path.Combine(WorkingDirectory, $"network_{DateTime.Now:yyyyMMdd_HHmmss}.inp");
|
||||||
var inpGenerator = new TSNetINPGenerator(Network, Configuration);
|
var inpGenerator = new TSNetINPGenerator(Network, Configuration, this);
|
||||||
|
|
||||||
await inpGenerator.GenerateAsync(inpPath);
|
await inpGenerator.GenerateAsync(inpPath);
|
||||||
CurrentInpFile = inpPath;
|
CurrentInpFile = inpPath;
|
||||||
|
@ -648,6 +664,7 @@ namespace CtrEditor.HydraulicSimulator.TSNet
|
||||||
|
|
||||||
var flows = new Dictionary<string, double>();
|
var flows = new Dictionary<string, double>();
|
||||||
var pressures = new Dictionary<string, double>();
|
var pressures = new Dictionary<string, double>();
|
||||||
|
var tankLevels = new Dictionary<string, double>(); // Niveles específicos de tanques
|
||||||
|
|
||||||
if (File.Exists(resultsFilePath))
|
if (File.Exists(resultsFilePath))
|
||||||
{
|
{
|
||||||
|
@ -668,6 +685,18 @@ namespace CtrEditor.HydraulicSimulator.TSNet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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<Dictionary<string, double>>(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
|
// Extraer flujos de tuberías
|
||||||
if (resultsData.ContainsKey("pipes"))
|
if (resultsData.ContainsKey("pipes"))
|
||||||
{
|
{
|
||||||
|
@ -680,7 +709,7 @@ namespace CtrEditor.HydraulicSimulator.TSNet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.WriteLine($"TSNet: Cargados {pressures.Count} presiones y {flows.Count} flujos");
|
Debug.WriteLine($"TSNet: Cargados {pressures.Count} presiones, {tankLevels.Count} niveles de tanques y {flows.Count} flujos");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -711,7 +740,39 @@ namespace CtrEditor.HydraulicSimulator.TSNet
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Aplicar resultados hidráulicos estándar (flujos y presiones)
|
||||||
hydraulicComponent.ApplyHydraulicResults(flows, pressures);
|
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++;
|
objectsProcessed++;
|
||||||
Debug.WriteLine($"TSNet: Resultados aplicados a {obj}");
|
Debug.WriteLine($"TSNet: Resultados aplicados a {obj}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,7 +201,15 @@ namespace CtrEditor.ObjetosSim
|
||||||
public double CurrentLevel
|
public double CurrentLevel
|
||||||
{
|
{
|
||||||
get => _currentLevel;
|
get => _currentLevel;
|
||||||
private set => SetProperty(ref _currentLevel, value);
|
private set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _currentLevel, value))
|
||||||
|
{
|
||||||
|
// Notificar que las propiedades dependientes también cambiaron
|
||||||
|
OnPropertyChanged(nameof(FillPercentage));
|
||||||
|
OnPropertyChanged(nameof(CurrentVolume));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Category("📊 Estado Actual")]
|
[Category("📊 Estado Actual")]
|
||||||
|
@ -259,7 +267,16 @@ namespace CtrEditor.ObjetosSim
|
||||||
public double CurrentLevelM
|
public double CurrentLevelM
|
||||||
{
|
{
|
||||||
get => _currentLevel;
|
get => _currentLevel;
|
||||||
set => SetProperty(ref _currentLevel, value);
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _currentLevel, value))
|
||||||
|
{
|
||||||
|
// Notificar que las propiedades dependientes también cambiaron
|
||||||
|
OnPropertyChanged(nameof(FillPercentage));
|
||||||
|
OnPropertyChanged(nameof(CurrentVolume));
|
||||||
|
OnPropertyChanged(nameof(CurrentLevel));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
Loading…
Reference in New Issue