CtrEditor/fix_tsnet_initial_head.py

232 lines
8.8 KiB
Python

#!/usr/bin/env python3
"""
Script para arreglar el problema 'Pipe' object has no attribute 'initial_head' en TSNet
Este error indica incompatibilidad entre TSNet y la versión de WNTR
"""
import sys
import os
import traceback
def fix_tsnet_initial_head_problem():
"""
Investiga y corrige el problema de 'initial_head' en TSNet
"""
print("=== Corrección del problema 'initial_head' en TSNet ===")
try:
import tsnet
import wntr
import numpy as np
print(f"✓ TSNet version: {tsnet.__version__}")
print(f"✓ WNTR version: {wntr.__version__}")
print(f"✓ NumPy version: {np.__version__}")
except ImportError as e:
print(f"✗ Error al importar: {e}")
return False
# Archivo INP problemático
inp_file_path = (
r"c:\Users\migue\AppData\Local\Temp\TSNet\network_20250911_235556.inp"
)
if not os.path.exists(inp_file_path):
print(f"✗ Archivo INP no encontrado: {inp_file_path}")
return False
print(f"✓ Archivo INP encontrado: {inp_file_path}")
try:
print("\n=== Investigando el problema de initial_head ===")
# Cargar modelo con WNTR primero
wn = wntr.network.WaterNetworkModel(inp_file_path)
print("✓ WNTR cargó el modelo exitosamente")
# Investigar las propiedades de los pipes en WNTR
print(f"\n=== Análisis de Pipes en WNTR ===")
for pipe_name in wn.pipe_name_list:
pipe = wn.get_link(pipe_name)
print(f"Pipe '{pipe_name}':")
print(f" - Tipo: {type(pipe)}")
# Listar todas las propiedades del pipe
pipe_attrs = [attr for attr in dir(pipe) if not attr.startswith("_")]
print(f" - Atributos disponibles: {len(pipe_attrs)}")
# Buscar atributos relacionados con 'head'
head_attrs = [attr for attr in pipe_attrs if "head" in attr.lower()]
print(f" - Atributos con 'head': {head_attrs}")
# Verificar si initial_head existe
if hasattr(pipe, "initial_head"):
print(f" - ✓ initial_head existe: {pipe.initial_head}")
else:
print(f" - ✗ initial_head NO existe")
# Buscar alternativas
alternatives = []
for attr in [
"head",
"initial_setting",
"start_node_name",
"end_node_name",
]:
if hasattr(pipe, attr):
alternatives.append(f"{attr}: {getattr(pipe, attr)}")
print(f" - Alternativas posibles: {alternatives}")
break # Solo analizar el primer pipe
print(f"\n=== Intentando cargar con TSNet ===")
# Intentar cargar con TSNet
tm = tsnet.network.TransientModel(inp_file_path)
print("✓ TSNet cargó el modelo")
# Verificar parámetros temporales (ya corregidos)
print(f" - simulation_period: {getattr(tm, 'simulation_period', 'N/A')}")
print(f" - time_step: {getattr(tm, 'time_step', 'N/A')}")
# Corregir parámetros si es necesario
if hasattr(tm, "simulation_period") and tm.simulation_period <= 0:
tm.simulation_period = 1.0
print(" - Corregido simulation_period = 1.0")
if hasattr(tm, "time_step") and tm.time_step <= 0:
tm.time_step = 0.1
print(" - Corregido time_step = 0.1")
print(f"\n=== Análisis de Links en TSNet ===")
if hasattr(tm, "links"):
print(f" - Número de links: {len(tm.links)}")
for i, link in enumerate(tm.links):
if hasattr(link, "__class__"):
print(f" - Link {i}: {link.__class__.__name__}")
# Verificar si es un Pipe y si tiene initial_head
if "Pipe" in str(type(link)):
print(f" * Es un Pipe")
link_attrs = [
attr for attr in dir(link) if not attr.startswith("_")
]
head_attrs = [
attr for attr in link_attrs if "head" in attr.lower()
]
print(f" * Atributos con 'head': {head_attrs}")
if hasattr(link, "initial_head"):
print(f" * ✓ initial_head existe: {link.initial_head}")
else:
print(f" * ✗ initial_head NO existe")
# Intentar crear/asignar initial_head
try:
# Opción 1: Asignar un valor por defecto
link.initial_head = 0.0
print(
f" * ✓ initial_head asignado: {link.initial_head}"
)
except Exception as e:
print(f" * ✗ No se pudo asignar initial_head: {e}")
# Opción 2: Buscar un método alternativo
if hasattr(link, "start_node") and hasattr(
link, "end_node"
):
try:
# Calcular head inicial basado en elevación de nodos
start_elev = getattr(
link.start_node, "elevation", 0.0
)
end_elev = getattr(
link.end_node, "elevation", 0.0
)
avg_elev = (start_elev + end_elev) / 2.0
link.initial_head = avg_elev
print(
f" * ✓ initial_head calculado: {link.initial_head}"
)
except Exception as e2:
print(
f" * ✗ Cálculo alternativo falló: {e2}"
)
if i >= 2: # Solo analizar los primeros 3 links
break
print(f"\n=== Intentando simulación TSNet corregida ===")
# Intentar simulación
try:
results = tsnet.simulation.MOCSimulator(
tm, results_obj="results", friction="steady"
)
print("🎉 ¡SIMULACIÓN TSNET EXITOSA!")
print("✓ El problema de 'initial_head' está resuelto")
return True
except Exception as sim_error:
print(f"✗ Error en simulación: {sim_error}")
error_str = str(sim_error).lower()
if "initial_head" in error_str:
print("\n💡 DIAGNÓSTICO ESPECÍFICO:")
print(
"1. TSNet requiere que todos los Pipe objects tengan 'initial_head'"
)
print("2. La versión actual de WNTR no proporciona este atributo")
print("3. Necesitamos monkey-patch o pre-procesamiento del modelo")
# Intentar monkey-patch
print("\n=== Intentando Monkey-Patch ===")
try:
# Asignar initial_head a todos los pipes
for link in tm.links:
if "Pipe" in str(type(link)) and not hasattr(
link, "initial_head"
):
link.initial_head = 0.0 # Valor por defecto
print("✓ Monkey-patch aplicado")
# Reintentar simulación
results = tsnet.simulation.MOCSimulator(
tm, results_obj="results", friction="steady"
)
print("🎉 ¡SIMULACIÓN EXITOSA CON MONKEY-PATCH!")
return True
except Exception as patch_error:
print(f"✗ Monkey-patch falló: {patch_error}")
return False
except Exception as e:
print(f"✗ Error: {e}")
traceback.print_exc()
return False
def main():
"""Función principal"""
success = fix_tsnet_initial_head_problem()
if success:
print("\n🎉 ¡PROBLEMA RESUELTO!")
print("TSNet puede ejecutar simulaciones sin fallback")
else:
print("\n❌ PROBLEMA NO RESUELTO")
print("Se requiere investigación adicional o actualización de dependencias")
return success
if __name__ == "__main__":
success = main()
sys.exit(0 if success else 1)