Browse Source

cambios CRIE-50-2020

oscarleiva 5 years ago
parent
commit
419eadb864

+ 27 - 0
create_shortcut.py

@@ -0,0 +1,27 @@
+import os
+
+import winshell
+from win32com.client import Dispatch
+
+
+def create_shortcut():
+    # creates shortcut
+    desktop = winshell.desktop()
+
+    path = os.path.join(desktop, "SimSDT.lnk")
+    target = os.path.join(
+        os.environ["LOCALAPPDATA"], "Merelec", "simsdt", "run.bat")
+    wDir = os.path.join(
+        os.environ["LOCALAPPDATA"], "Merelec", "simsdt")
+    icon = os.path.join(os.environ["LOCALAPPDATA"],
+                        "Merelec", "simsdt", "app.ico")
+    shell = Dispatch('WScript.Shell')
+    shortcut = shell.CreateShortCut(path)
+    shortcut.Targetpath = target
+    shortcut.WorkingDirectory = wDir
+    shortcut.IconLocation = icon
+    shortcut.save()
+
+
+if __name__ == "__main__":
+    create_shortcut()

+ 67 - 0
install.bat

@@ -0,0 +1,67 @@
+@echo off
+
+echo ============================================================
+echo             Instalación del Sistema de Simulación
+echo             de Subastas de Derechos de Transmisión
+echo             Mercados Eléctricos de Centroamérica
+echo ============================================================
+
+echo Instalando SimSDT
+REM echo Descargando Python...
+REM powershell -command "& { (New-Object Net.WebClient).DownloadFile('https://repo.anaconda.com/miniconda/Miniconda3-latest-Windows-x86_64.exe', 'mc3.exe') }"
+
+echo ============================================================
+echo Instalando Python...
+start /wait "" mc3.exe /InstallationType=JustMe /AddToPath=0 /RegisterPython=0 /NoRegistry=1 /S /D=%LOCALAPPDATA%\Merelec\simsdt\mc3
+echo Python se instalo correctamente...
+echo Verificando la version de Python
+
+%LOCALAPPDATA%\Merelec\spr\mc3\python.exe --version
+
+echo ============================================================
+echo Copiando archivos del Sistema...
+
+%LOCALAPPDATA%\Merelec\spr\mc3\python.exe install_copy_files.py
+
+echo Seteando variables de entorno...
+
+SET PATH=%PATH%;%LOCALAPPDATA%\Merelec\simsdt\mc3;%LOCALAPPDATA%\Merelec\simsdt\mc3\Scripts;%LOCALAPPDATA%\Merelec\simsdt\mc3\Library;%LOCALAPPDATA%\Merelec\simsdt\mc3\Library\bin
+
+cd %LOCALAPPDATA%\Merelec\simsdt
+
+mkdir log
+mkdir config
+mkdir data
+
+echo Actualizando la version de pip
+
+%LOCALAPPDATA%\Merelec\simsdt\mc3\python.exe -m pip install --upgrade pip
+
+echo Fin de actualización de pip
+
+echo Instalando paquetes necesarios
+
+%LOCALAPPDATA%\Merelec\simsdt\mc3\Scripts\pip.exe install -r requirements.txt
+
+echo ============================================================
+echo Instalando Solver IPOPT...
+echo Agregando IPOPT to Path
+
+setx /M PATH "%PATH%;%LOCALAPPDATA%\Merelec\simsdt\ipopt\bin"
+
+echo Verificando instalación de Ipopt
+
+ipopt --version
+echo ============================================================
+
+
+
+echo Creando Acceso directo en el escritorio...
+%LOCALAPPDATA%\Merelec\simsdt\mc3\python.exe create_shortcut.py
+
+echo ============================================================
+echo                   Instalación Finalizada
+echo             Mercados Eléctricos de Centroamérica
+echo ============================================================
+
+pause

+ 28 - 0
install_copy_files.py

@@ -0,0 +1,28 @@
+import os
+import shutil
+
+unrequired_files = ("install.bat", "install_copy_files.py",
+                    "mc3.exe", "miniconda_install.bat", ".git")
+
+
+def install():
+
+    print("Instalando el Sistema de Simulación de Subastas de Derechos Firmes")
+
+    # Crear una carpeta en donde se copien e instalen todos los archivos
+    idir = os.path.join(os.environ["LOCALAPPDATA"], "Merelec", "simsdt")
+
+    if os.path.exists(idir):
+        # Copiamos todos las carpetas y archivos al directorio de instalacion
+
+        print("Copiando archivos del sistema")
+        shutil.copytree(os.curdir, idir,
+                        ignore=shutil.ignore_patterns(
+                            "install.bat", "install_copy_files.py", "mc3.exe",
+                            "miniconda_install.bat", ".git", ".vscode",
+                            ".gitignore"),
+                        dirs_exist_ok=True)
+
+
+if __name__ == "__main__":
+    install()

+ 1 - 0
requirements.txt

@@ -24,3 +24,4 @@ pywin32-ctypes==0.2.0
 scipy==1.4.1
 scipy==1.4.1
 six==1.15.0
 six==1.15.0
 xlrd==1.2.0
 xlrd==1.2.0
+winshell==0.6

+ 5 - 0
run.bat

@@ -0,0 +1,5 @@
+@echo off
+call %LOCALAPPDATA%\Merelec\spr\mc3\Scripts\activate.bat
+start /b %LOCALAPPDATA%\Merelec\spr\mc3\pythonw.exe main.py
+
+

+ 54 - 0
simsdt/mct/makeEXP.py

@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+# =============================================================================
+#  Copyright (C) 2018 Mercados Electricos de Centroamérica. All rights reserved
+# =============================================================================
+
+"""Crea limites de trasnferencia entre área de Control 
+"""
+from numpy import argwhere
+from pandas import read_excel
+
+# Se definen las líneas que componenn las interconexiones entre las areas de
+# control
+
+__GUA = []
+__ES = []
+__HON = []
+__NIC = []
+__CR = []
+__PAN = []
+
+__INTER = {'GUA': __GUA,
+           'ES': __ES,
+           'HON': __HON,
+           'NIC': __NIC,
+           'CR': __CR,
+           'PAN': __PAN
+           }
+
+
+def linexp(brnames):
+    """Construye un diccionario con el indice que corresponde al nombre del
+    los paises exp/int
+    """
+    lexp = {}
+
+    for item in __INTER:
+        lexp[item] = []
+        for i in __INTER[item]:
+            try:
+
+                l = int(argwhere(brnames == i))
+                lexp[item].append(l)
+            except Exception:
+                0
+    return lexp
+
+
+def readexp(file):
+    """Lee la información de Máximas Capacidades de Trasnferencia del archivo
+    Excel del caso a resolver.
+    """
+    exp = read_excel(file, 'exp', index_col=[0, 1, 2])
+
+    return exp

+ 20 - 14
simsdt/mct/makeMCT.py

@@ -3,7 +3,7 @@
 #  Copyright (C) 2018 Mercados Electricos de Centroamérica. All rights reserved
 #  Copyright (C) 2018 Mercados Electricos de Centroamérica. All rights reserved
 # =============================================================================
 # =============================================================================
 
 
-"""Crea limites de trasnferencia entre área de Control
+"""Crea limites de trasnferencia entre área de Control 
 """
 """
 from numpy import argwhere
 from numpy import argwhere
 from pandas import read_excel
 from pandas import read_excel
@@ -11,19 +11,21 @@ from pandas import read_excel
 # Se definen las líneas que componenn las interconexiones entre las areas de
 # Se definen las líneas que componenn las interconexiones entre las areas de
 # control
 # control
 
 
-__GUAESA = ['1126-29162-1', '1124-29161-1']
 __GUAHON = ['1710-3190-1']
 __GUAHON = ['1710-3190-1']
-__ESAHON = ['28181-29181-1', '28181-29182-2']
+__GUAELS = ['1126-29162-1', '1124-29161-1']
+__ELSHON = ['28181-29181-1', '28181-29182-2']
 __HONNIC = ['3301-4411-1', '3310-4407-1']
 __HONNIC = ['3301-4411-1', '3310-4407-1']
-__NICCRC = ['4412-50050-1', '4408-50000-1']
-__CRCPAN = ['6500-56050-1', '6400-58350-1', '6000-56050-1']
+__NICCRI = ['4406-4412-1', '4750-4408-1']
+__CRIPAN = ['6500-56050-1', '6400-58350-1', '6000-56050-1']
 
 
-__INTER = {'GUAESA': __GUAESA,
-           'GUAHON': __GUAHON,
-           'ESAHON': __ESAHON,
+
+__INTER = {'GUAHON': __GUAHON,
+           'GUAELS': __GUAELS,
+           'ELSHON': __ELSHON,
            'HONNIC': __HONNIC,
            'HONNIC': __HONNIC,
-           'NICCRC': __NICCRC,
-           'CRCPAN': __CRCPAN}
+           'NICCRI': __NICCRI,
+           'CRIPAN': __CRIPAN
+           }
 
 
 
 
 def linmct(brnames):
 def linmct(brnames):
@@ -35,9 +37,12 @@ def linmct(brnames):
     for item in __INTER:
     for item in __INTER:
         lmct[item] = []
         lmct[item] = []
         for i in __INTER[item]:
         for i in __INTER[item]:
-            l = int(argwhere(brnames == i))
-            lmct[item].append(l)
+            try:
 
 
+                l = int(argwhere(brnames == i))
+                lmct[item].append(l)
+            except Exception:
+                0
     return lmct
     return lmct
 
 
 
 
@@ -45,7 +50,7 @@ def readmct(file):
     """Lee la información de Máximas Capacidades de Trasnferencia del archivo
     """Lee la información de Máximas Capacidades de Trasnferencia del archivo
     Excel del caso a resolver.
     Excel del caso a resolver.
     """
     """
-    mct = read_excel(file, 'mct', index_col=[0, 1])
+    mct = read_excel(file, 'mct', index_col=[0, 1, 2])
 
 
     return mct
     return mct
 
 
@@ -61,8 +66,9 @@ def set_dir_flujo():
     d = {}
     d = {}
 
 
     for key in __INTER.keys():
     for key in __INTER.keys():
-        if key == 'CRCPAN':
+        if key == 'CRIPAN':
             d[key] = -1
             d[key] = -1
+
         else:
         else:
             d[key] = 1
             d[key] = 1
 
 

+ 11 - 0
simsdt/mct/makeMCTP.py

@@ -0,0 +1,11 @@
+
+from pandas import read_excel
+
+
+def readmctp(file):
+    """Lee la información de Máximas Capacidades de Trasnferencia del archivo
+    Excel del caso a resolver.
+    """
+    mctp = read_excel(file, 'mctp', index_col=[0, 1])
+
+    return mctp

+ 432 - 298
simsdt/model.py

@@ -9,11 +9,15 @@ from os import path
 import pandas as pd
 import pandas as pd
 import pyomo.environ as pe
 import pyomo.environ as pe
 import pyutilib.subprocess.GlobalData
 import pyutilib.subprocess.GlobalData
+from common.data import APPDIRS
 from numpy import array, zeros
 from numpy import array, zeros
+from pandas import ExcelWriter
 from pyomo.environ import SolverFactory
 from pyomo.environ import SolverFactory
+from validacion.validacion import validar_flujos
 
 
-from common.data import APPDIRS
+from simsdt.mct.makeEXP import linexp, readexp
 from simsdt.mct.makeMCT import linmct, readmct, set_dir_flujo
 from simsdt.mct.makeMCT import linmct, readmct, set_dir_flujo
+from simsdt.mct.makeMCTP import readmctp
 from simsdt.ofertas.readBids import (readexistentes, readofertas, setT, setTE,
 from simsdt.ofertas.readBids import (readexistentes, readofertas, setT, setTE,
                                      setVIT, setVITE, setVITEX, setVITX,
                                      setVIT, setVITE, setVITEX, setVITX,
                                      setVRT, setVRTE)
                                      setVRT, setVRTE)
@@ -32,9 +36,11 @@ model_logger = logging.getLogger('simsdt.model')
 
 
 class ModeloSubasta:
 class ModeloSubasta:
 
 
-    def __init__(self, file, tee=True):
+    def __init__(self, file, p_exec, all_year=True, tee=True):
         self.file = file
         self.file = file
         self.tee = tee
         self.tee = tee
+        self.p_exec = p_exec
+        self.all_year = all_year
 
 
     def setmodel(self):
     def setmodel(self):
         model_logger.info('Modelo de Subasta de Derechos Firmes')
         model_logger.info('Modelo de Subasta de Derechos Firmes')
@@ -51,8 +57,7 @@ class ModeloSubasta:
         model_logger.info(
         model_logger.info(
             "Leyendo información de ofertas y derechos firmes existentes")
             "Leyendo información de ofertas y derechos firmes existentes")
 
 
-        ex = readexistentes(self.file)
-        nex = ex.shape[0]
+        ex_t = readexistentes(self.file)
         of = readofertas(self.file)
         of = readofertas(self.file)
         nof = of.shape[0]
         nof = of.shape[0]
 
 
@@ -83,9 +88,17 @@ class ModeloSubasta:
 
 
         # Lineas para límites de MCT
         # Lineas para límites de MCT
         lin_mct = linmct(brnames)
         lin_mct = linmct(brnames)
-        mct = readmct(self.file)/100
+        mct = readmct(self.file)
         dirf = set_dir_flujo()
         dirf = set_dir_flujo()
 
 
+        # Max impo/exp
+        lin_exp = linexp(brnames)
+        exp = readexp(self.file)
+
+        # Lectura de MCTP
+        model_logger.info("Leyendo los MCTP para validación posterior")
+        mctp = readmctp(self.file)
+
         model_logger.info("Cálculando la matriz H")
         model_logger.info("Cálculando la matriz H")
         # Cálculo de la matriz H
         # Cálculo de la matriz H
         H = makePTDF(bus, branch)
         H = makePTDF(bus, branch)
@@ -95,405 +108,526 @@ class ModeloSubasta:
         _, _, A = makeBdc(bus, branch)
         _, _, A = makeBdc(bus, branch)
         inc = A.toarray()**2
         inc = A.toarray()**2
 
 
-        model_logger.info("Creando Vectores de Derechos Firmes existentes")
-        # Datos de los Derechos Firmes Existentes
-        vite = setVITE(bus, ex)/100
-        vrte = setVRTE(bus, ex)/100
-        vitex = setVITEX(bus, ex)/100
-        te = setTE(vite, vrte)
-
-        model_logger.info("Creando vectores de Ofertas de Derechos firmes")
-        # Datos de las ofertas de Derechos Firmes
-        c = of.oferta.values
-        cper = of.cper.values
-        perk = of.per.values/100
-        vit = setVIT(bus, of)/100
-        vrt = setVRT(bus, of)/100
-        vitx = setVITX(bus, of)/100
-        t = setT(vit, vrt)
-
-        # ============================================================================
-        # Modelo de optimización subasta de derechos Firmes
-        # ============================================================================
-
-        model_logger.info("Inicio del problema de Optimización")
-        # Inicio del modelo de optimización
-
-        model = pe.ConcreteModel()
-
-        # SETS
-
-        model_logger.info("Creando Sets del problema")
-        model.c = pe.Set(initialize=range(0, nbr))   # Número de circuitos
-        model.n = pe.Set(initialize=range(0, nb))    # Número de nodos
-        model.o = pe.Set(initialize=range(0, nex))   # Número de DF existentes
-        model.k = pe.Set(initialize=range(0, nof))   # Número de Ofertas DF
-        model.i = pe.Set(initialize=lin_mct.keys())  # Interconexiones
-        # Sentidos de interconexiones
-        model.s = pe.Set(initialize=['sn', 'ns'])
-
-        # PARAMETERS
+        # model_logger.info("Creando Vectores de Derechos Firmes existentes")
+        # # Datos de los Derechos Firmes Existentes
+        # vite = setVITE(bus, ex)/100
+        # vrte = setVRTE(bus, ex)/100
+        # vitex = setVITEX(bus, ex)/100
+        # te = setTE(vite, vrte)
+
+        for Mes in range(1, 2):
+            model_logger.info(f"Ejecutando para el mes {Mes}")
+            model_logger.info("Creando vectores de Ofertas de Derechos firmes")
+            # Datos de las ofertas de Derechos Firmes
+            c = of.oferta.values
+            cper = of.cper.values
+            perk = of.per.values/100
+            vit = setVIT(bus, of)/100
+            vrt = setVRT(bus, of)/100
+            vitx = setVITX(bus, of)/100
+            t = setT(vit, vrt)
+
+            # Filtra las ofertas existentes por Mes
+            ex = ex_t[ex_t.mes_vig.isin([Mes])].copy()
+            ex.reset_index(drop=True, inplace=True)  # Reset de indices del df
+            # Quitamos la columna de Mes para usar la funciones
+            ex.drop(['mes_vig'], axis='columns', inplace=True)
+
+            nex = ex.shape[0]
+
+            model_logger.info("Creando Vectores de Derechos Firmes existentes")
+            # Datos de los Derechos Firmes Existentes
+            vite = setVITE(bus, ex)/100
+            vrte = setVRTE(bus, ex)/100
+            vitex = setVITEX(bus, ex)/100
+            te = setTE(vite, vrte)
+
+            # ============================================================================
+            # Modelo de optimización subasta de derechos Firmes
+            # ============================================================================
+
+            model_logger.info("Inicio del problema de Optimización")
+            # Inicio del modelo de optimización
+
+            model = pe.ConcreteModel()
+
+            # SETS
+
+            model_logger.info("Creando Sets del problema")
+            model.c = pe.Set(initialize=range(0, nbr))   # Número de circuitos
+            model.n = pe.Set(initialize=range(0, nb))    # Número de nodos
+            # Número de DF existentes
+            model.o = pe.Set(initialize=range(0, nex))
+            model.k = pe.Set(initialize=range(0, nof))   # Número de Ofertas DF
+            model.i = pe.Set(initialize=lin_mct.keys())  # Interconexiones
+            model.p = pe.Set(initialize=lin_exp.keys())  # Paises
+
+            # Sentidos de interconexiones
+            model.s = pe.Set(initialize=['sn', 'ns'])
+            model.trans = pe.Set(initialize=['i', 'e'])
+            model.m = pe.Set(initialize=range(1, 12))
+
+            # PARAMETERS
+
+            model_logger.info("Creando Parametros del problema")
+            # Ofertas derechos firmes
+            model_logger.info("Parametros de Ofertas de Derechos Firmes")
+            model.C = pe.Param(model.k, initialize=dict(enumerate(c)))
+            model.Cper = pe.Param(model.k, initialize=dict(enumerate(cper)))
+            model.Perk = pe.Param(model.k, initialize=dict(enumerate(perk)))
+
+            # Parametros de la red
+
+            model_logger.info("Parametros de Red")
+            model.Bu = pe.Param(model.c, initialize=dict(enumerate(bu)))
+            model.Bl = pe.Param(model.c, initialize=dict(enumerate(bl)))
+            model.R = pe.Param(model.c, initialize=dict(enumerate(r)))
+            model.Inc = pe.Param(model.c, model.n, initialize=arr2dict(inc))
+
+            # elemento H[c,n]
+
+            model_logger.info("Parametros de Matriz H")
+            model.He = pe.Param(model.c, model.n, initialize=arr2dict(H))
+
+            model_logger.info("Parametros de Derechos Firmes Existentes")
+            # Vector de inyecciones df existentes
+            model.VITE = pe.Param(model.n, model.o, initialize=arr2dict(vite))
+            # Vector de retiros df existentes
+            model.VRTE = pe.Param(model.n, model.o, initialize=arr2dict(vrte))
+            # Vector de perididas df existentes
+            model.VITEX = pe.Param(
+                model.n, model.o, initialize=arr2dict(vitex))
+            # DF existentes
+            model.TE = pe.Param(model.n, model.o, initialize=arr2dict(te))
 
 
-        model_logger.info("Creando Parametros del problema")
-        # Ofertas derechos firmes
-        model_logger.info("Parametros de Ofertas de Derechos Firmes")
-        model.C = pe.Param(model.k, initialize=dict(enumerate(c)))
-        model.Cper = pe.Param(model.k, initialize=dict(enumerate(cper)))
-        model.Perk = pe.Param(model.k, initialize=dict(enumerate(perk)))
+            model_logger.info("Parametros de Inyecciones y Retiros de Ofertas")
+            # Vector inyecciones ofertas de compra df
+            model.VIT = pe.Param(model.n, model.k, initialize=arr2dict(vit))
+            # Vector retiros ofertas de compra df
+            model.VRT = pe.Param(model.n, model.k, initialize=arr2dict(vrt))
+            # Vector inyecciones perdidas oferta de compra df
+            model.VITX = pe.Param(model.n, model.k, initialize=arr2dict(vitx))
+            # Ofertas de compora DF
+            model.T = pe.Param(model.n, model.k, initialize=arr2dict(t))
 
 
-        # Parametros de la red
+            model_logger.info("Parametros de Limites de flujos en las líneas")
 
 
-        model_logger.info("Parametros de Red")
-        model.Bu = pe.Param(model.c, initialize=dict(enumerate(bu)))
-        model.Bl = pe.Param(model.c, initialize=dict(enumerate(bl)))
-        model.R = pe.Param(model.c, initialize=dict(enumerate(r)))
-        model.Inc = pe.Param(model.c, model.n, initialize=arr2dict(inc))
+            # Lim. Superior flujos asociados a linea c
+            def bfu_param(model, c):
+                return model.Bu[c]
+                - sum(max(0, sum(model.He[c, n]*model.TE[n, o]
+                                 for n in model.n)) for o in model.o)
 
 
-        # elemento H[c,n]
+            model.BFu = pe.Param(model.c, initialize=bfu_param)
 
 
-        model_logger.info("Parametros de Matriz H")
-        model.He = pe.Param(model.c, model.n, initialize=arr2dict(H))
+            # LIm. Inferior flujos asociados a linea c
+            def bfl_param(model, c):
+                return model.Bl[c]
+                - sum(max(0, -sum(model.He[c, n]*model.TE[n, o]
+                                  for n in model.n)) for o in model.o)
 
 
-        model_logger.info("Parametros de Derechos Firmes Existentes")
-        # Vector de inyecciones df existentes
-        model.VITE = pe.Param(model.n, model.o, initialize=arr2dict(vite))
-        # Vector de retiros df existentes
-        model.VRTE = pe.Param(model.n, model.o, initialize=arr2dict(vrte))
-        # Vector de perididas df existentes
-        model.VITEX = pe.Param(model.n, model.o, initialize=arr2dict(vitex))
-        # DF existentes
-        model.TE = pe.Param(model.n, model.o, initialize=arr2dict(te))
+            model.BFl = pe.Param(model.c, initialize=bfl_param)
 
 
-        model_logger.info("Parametros de Inyecciones y Retiros de Ofertas")
-        # Vector inyecciones ofertas de compra df
-        model.VIT = pe.Param(model.n, model.k, initialize=arr2dict(vit))
-        # Vector retiros ofertas de compra df
-        model.VRT = pe.Param(model.n, model.k, initialize=arr2dict(vrt))
-        # Vector inyecciones perdidas oferta de compra df
-        model.VITX = pe.Param(model.n, model.k, initialize=arr2dict(vitx))
-        # Ofertas de compora DF
-        model.T = pe.Param(model.n, model.k, initialize=arr2dict(t))
+            # Máximas Capacidades de Trasferencia
+            model.Mct = pe.Param(
+                model.i, model.s, model.m, initialize=mct.mct.to_dict())
+            model.DirF = pe.Param(model.i, initialize=dirf)
 
 
-        model_logger.info("Parametros de Limites de flujos en las líneas")
+            # Maxima Imp/Exp
+            model.Imp = pe.Param(model.p, model.trans, model.m,
+                                 initialize=exp.MW.to_dict())
 
 
-        # Lim. Superior flujos asociados a linea c
-        def bfu_param(model, c):
-            return model.Bu[c]
-            - sum(max(0, sum(model.He[c, n]*model.TE[n, o]
-                             for n in model.n)) for o in model.o)
+            # VARIABLES
 
 
-        model.BFu = pe.Param(model.c, initialize=bfu_param)
+            model_logger.info("Creando Variables del problema")
+            # Variables primales
 
 
-        # LIm. Inferior flujos asociados a linea c
-        def bfl_param(model, c):
-            return model.Bl[c]
-            - sum(max(0, -sum(model.He[c, n]*model.TE[n, o]
-                              for n in model.n)) for o in model.o)
+            model.alpha_k = pe.Var(
+                model.k, within=pe.NonNegativeReals, bounds=(0, 1))
+            model.gamma_k = pe.Var(model.k, within=pe.NonNegativeReals)
 
 
-        model.BFl = pe.Param(model.c, initialize=bfl_param)
+            # Flujos
 
 
-        # Máximas Capacidades de Trasferencia
-        model.Mct = pe.Param(model.i, model.s, initialize=mct.mct.to_dict())
-        model.DirF = pe.Param(model.i, initialize=dirf)
+            model.F = pe.Var(model.c)
+            model.PL = pe.Var(model.c)
+            model.Per = pe.Var(model.n)
+            model.F_k = pe.Var(model.c, model.k)
+            model.Fp_k = pe.Var(model.c, model.k, within=pe.NonNegativeReals)
+            model.Fp = pe.Var(model.c, within=pe.NonNegativeReals)
+            model.Fn_k = pe.Var(model.c, model.k, within=pe.NonNegativeReals)
+            model.Fn = pe.Var(model.c, within=pe.NonNegativeReals)
 
 
-        # VARIABLES
+            # EQUATIONS
 
 
-        model_logger.info("Creando Variables del problema")
-        # Variables primales
+            model_logger.info("Creando Ecuaciones del problema")
+            # Ecuación Objetivo
+            # =============================================================================
 
 
-        model.alpha_k = pe.Var(
-            model.k, within=pe.NonNegativeReals, bounds=(0, 1))
-        model.gamma_k = pe.Var(model.k, within=pe.NonNegativeReals)
+            model_logger.info("Ecuación de Función Objetivo Max Z")
 
 
-        # Flujos
+            def eq_Z(model):
+                return sum(model.alpha_k[k]*model.C[k]
+                           - model.gamma_k[k]*model.Cper[k] for k in model.k)
 
 
-        model.F = pe.Var(model.c)
-        model.PL = pe.Var(model.c)
-        model.Per = pe.Var(model.n)
-        model.F_k = pe.Var(model.c, model.k)
-        model.Fp_k = pe.Var(model.c, model.k, within=pe.NonNegativeReals)
-        model.Fp = pe.Var(model.c, within=pe.NonNegativeReals)
-        model.Fn_k = pe.Var(model.c, model.k, within=pe.NonNegativeReals)
-        model.Fn = pe.Var(model.c, within=pe.NonNegativeReals)
+            model.Z = pe.Objective(rule=eq_Z, sense=pe.maximize)
 
 
-        # EQUATIONS
+            # Restricciones
+            # =============================================================================
 
 
-        model_logger.info("Creando Ecuaciones del problema")
-        # Ecuación Objetivo
-        # =============================================================================
+            model_logger.info("Restricciones del Modelo de Optimización")
+            model_logger.info("Límites de Gamma")
 
 
-        model_logger.info("Ecuación de Función Objetivo Max Z")
+            def eq_gamma_k_rule(model, k):
+                return model.gamma_k[k] <= model.alpha_k[k]
 
 
-        def eq_Z(model):
-            return sum(model.alpha_k[k]*model.C[k]
-                       - model.gamma_k[k]*model.Cper[k] for k in model.k)
+            model.eq_gamma_k = pe.Constraint(model.k, rule=eq_gamma_k_rule)
 
 
-        model.Z = pe.Objective(rule=eq_Z, sense=pe.maximize)
+            # Factibilidad de derechos firmes
 
 
-        # Restricciones
-        # =============================================================================
+            model_logger.info("Factibilidad de derechos Firmes")
 
 
-        model_logger.info("Restricciones del Modelo de Optimización")
-        model_logger.info("Límites de Gamma")
+            def eq_F_k_rule(model, c, k):
+                return model.F_k[c, k] == (
+                    model.alpha_k[k] *
+                    sum(model.He[c, n] * model.T[n, k] for n in model.n))
 
 
-        def eq_gamma_k_rule(model, k):
-            return model.gamma_k[k] <= model.alpha_k[k]
+            model.eq_F_k = pe.Constraint(model.c, model.k, rule=eq_F_k_rule)
 
 
-        model.eq_gamma_k = pe.Constraint(model.k, rule=eq_gamma_k_rule)
+            # Flujos positivos
 
 
-        # Factibilidad de derechos firmes
+            model_logger.info("Flujos positivos")
 
 
-        model_logger.info("Factibilidad de derechos Firmes")
+            def eq_Fp_k_rule(model, c, k):
+                return model.Fp_k[c, k] >= model.F_k[c, k]
 
 
-        def eq_F_k_rule(model, c, k):
-            return model.F_k[c, k] == (
-                model.alpha_k[k] *
-                sum(model.He[c, n] * model.T[n, k] for n in model.n))
+            model.eq_Fp_k = pe.Constraint(model.c, model.k, rule=eq_Fp_k_rule)
 
 
-        model.eq_F_k = pe.Constraint(model.c, model.k, rule=eq_F_k_rule)
+            def eq_Fp_rule(model, c):
+                return model.Fp[c] == sum(model.Fp_k[c, k] for k in model.k)
 
 
-        # Flujos positivos
+            model.eq_Fp = pe.Constraint(model.c, rule=eq_Fp_rule)
 
 
-        model_logger.info("Flujos positivos")
+            def eq_Fpl_rule(model, c):
+                return sum(model.Fp_k[c, k] for k in model.k) <= model.BFu[c]
 
 
-        def eq_Fp_k_rule(model, c, k):
-            return model.Fp_k[c, k] >= model.F_k[c, k]
+            model.eq_Fpl = pe.Constraint(model.c, rule=eq_Fpl_rule)
 
 
-        model.eq_Fp_k = pe.Constraint(model.c, model.k, rule=eq_Fp_k_rule)
+            # Flujos negativos
 
 
-        def eq_Fp_rule(model, c):
-            return model.Fp[c] == sum(model.Fp_k[c, k] for k in model.k)
+            model_logger.info("Flujos negativos")
 
 
-        model.eq_Fp = pe.Constraint(model.c, rule=eq_Fp_rule)
+            def eq_Fn_k_rule(model, c, k):
+                return model.Fn_k[c, k] >= -model.F_k[c, k]
 
 
-        def eq_Fpl_rule(model, c):
-            return sum(model.Fp_k[c, k] for k in model.k) <= model.BFu[c]
+            model.eq_Fn_k = pe.Constraint(model.c, model.k, rule=eq_Fn_k_rule)
 
 
-        model.eq_Fpl = pe.Constraint(model.c, rule=eq_Fpl_rule)
+            def eq_Fn_rule(model, c):
+                return model.Fn[c] == sum(model.Fn_k[c, k] for k in model.k)
 
 
-        # Flujos negativos
+            model.eq_Fn = pe.Constraint(model.c, rule=eq_Fn_rule)
 
 
-        model_logger.info("Flujos negativos")
+            def eq_Fnl_rule(model, c):
+                return sum(model.Fn_k[c, k] for k in model.k) <= model.BFl[c]
 
 
-        def eq_Fn_k_rule(model, c, k):
-            return model.Fn_k[c, k] >= -model.F_k[c, k]
+            model.eq_Fnl = pe.Constraint(model.c, rule=eq_Fnl_rule)
 
 
-        model.eq_Fn_k = pe.Constraint(model.c, model.k, rule=eq_Fn_k_rule)
+            # Suficiencia Financiera
 
 
-        def eq_Fn_rule(model, c):
-            return model.Fn[c] == sum(model.Fn_k[c, k] for k in model.k)
+            model_logger.info("Suficiencia Financiera")
 
 
-        model.eq_Fn = pe.Constraint(model.c, rule=eq_Fn_rule)
+            def eq_sf1_rule(model, c):
+                return model.F[c] <= model.Bu[c]
 
 
-        def eq_Fnl_rule(model, c):
-            return sum(model.Fn_k[c, k] for k in model.k) <= model.BFl[c]
+            model.eq_sf1 = pe.Constraint(model.c, rule=eq_sf1_rule)
 
 
-        model.eq_Fnl = pe.Constraint(model.c, rule=eq_Fnl_rule)
+            def eq_sf2_rule(model, c):
+                return model.F[c] >= -model.Bl[c]
 
 
-        # Suficiencia Financiera
+            model.eq_sf2 = pe.Constraint(model.c, rule=eq_sf2_rule)
 
 
-        model_logger.info("Suficiencia Financiera")
+            # Balance de Pérdidas
 
 
-        def eq_sf1_rule(model, c):
-            return model.F[c] <= model.Bu[c]
+            model_logger.info("Balance de Pérdidas")
 
 
-        model.eq_sf1 = pe.Constraint(model.c, rule=eq_sf1_rule)
+            def eq_PL_rule(model, c):
+                return model.PL[c] == model.R[c]*(model.F[c]*model.F[c])
 
 
-        def eq_sf2_rule(model, c):
-            return model.F[c] >= -model.Bl[c]
+            model.eq_PL = pe.Constraint(model.c, rule=eq_PL_rule)
 
 
-        model.eq_sf2 = pe.Constraint(model.c, rule=eq_sf2_rule)
+            def eq_Per_rule(model, n):
+                return model.Per[n] == (
+                    sum(model.Inc[c, n]*(model.PL[c]/2) for c in model.c))
 
 
-        # Balance de Pérdidas
+            model.eq_Per = pe.Constraint(model.n, rule=eq_Per_rule)
 
 
-        model_logger.info("Balance de Pérdidas")
+            # Balance de Flujos
 
 
-        def eq_PL_rule(model, c):
-            return model.PL[c] == model.R[c]*(model.F[c]*model.F[c])
+            model_logger.info("Balance de Flujos")
 
 
-        model.eq_PL = pe.Constraint(model.c, rule=eq_PL_rule)
+            def eq_Balance_rule(model, c):
+                return model.F[c] == sum(model.He[c, n]*(
+                    sum(model.alpha_k[k]*model.T[n, k] for k in model.k) +
+                    sum(model.TE[n, o] for o in model.o) +
+                    sum(model.gamma_k[k]*model.VITX[n, k] for k in model.k) +
+                    sum(model.VITEX[n, o]for o in model.o) -
+                    model.Per[n]) for n in model.n)
 
 
-        def eq_Per_rule(model, n):
-            return model.Per[n] == (
-                sum(model.Inc[c, n]*(model.PL[c]/2) for c in model.c))
+            model.eq_Balance = pe.Constraint(model.c, rule=eq_Balance_rule)
 
 
-        model.eq_Per = pe.Constraint(model.n, rule=eq_Per_rule)
+            # Perdidas en estado base
 
 
-        # Balance de Flujos
+            model_logger.info("Perdidas en estado Base")
 
 
-        model_logger.info("Balance de Flujos")
+            def eq_perdidas_base_rule(model):
+                return sum(model.PL[c] for c in model.c) == sum(
+                    sum(model.gamma_k[k]*model.VITX[n, k] for k in model.k) +
+                    sum(model.VITEX[n, o] for o in model.o) for n in model.n)
 
 
-        def eq_Balance_rule(model, c):
-            return model.F[c] == sum(model.He[c, n]*(
-                sum(model.alpha_k[k]*model.T[n, k] for k in model.k) +
-                sum(model.TE[n, o] for o in model.o) +
-                sum(model.gamma_k[k]*model.VITX[n, k] for k in model.k) +
-                sum(model.VITEX[n, o]for o in model.o) -
-                model.Per[n]) for n in model.n)
+            model.eq_perdidas_base = pe.Constraint(rule=eq_perdidas_base_rule)
 
 
-        model.eq_Balance = pe.Constraint(model.c, rule=eq_Balance_rule)
+            # Máximas capacidades de trasferencia entre áreas de control
 
 
-        # Perdidas en estado base
+            model_logger.info(
+                "Máxima Capacidad de Trasnferencia entre áreas de control")
 
 
-        model_logger.info("Perdidas en estado Base")
+            def eq_mct_ns_rule(model, i):
+                return sum(model.DirF[i]*model.F[c] for c in lin_mct[i]) <= \
+                    model.Mct[i, 'ns', Mes]/100
 
 
-        def eq_perdidas_base_rule(model):
-            return sum(model.PL[c] for c in model.c) == sum(
-                sum(model.gamma_k[k]*model.VITX[n, k] for k in model.k) +
-                sum(model.VITEX[n, o] for o in model.o) for n in model.n)
+            model.eq_mct_ns = pe.Constraint(model.i, rule=eq_mct_ns_rule)
 
 
-        model.eq_perdidas_base = pe.Constraint(rule=eq_perdidas_base_rule)
+            def eq_mct_sn_rule(model, i):
+                return sum(model.DirF[i]*model.F[c] for c in lin_mct[i]) >= \
+                    -model.Mct[i, 'sn', Mes]/100
 
 
-        # Máximas capacidades de trasferencia entre áreas de control
+            model.eq_mct_sn = pe.Constraint(model.i, rule=eq_mct_sn_rule)
 
 
-        model_logger.info(
-            "Máxima Capacidad de Trasnferencia entre áreas de control")
+            # Maxima importacion/exportacion
+            def eq_imp_i_rule(model, p):
+                if p == 'ES':  # Maxima exportacion de El Salvador
+                    return ((sum(model.F[c] for c in lin_mct['ELSHON'])) -
+                            (sum(model.F[c] for c in lin_mct['GUAELS']))) <= model.Imp[p, 'e', Mes]/100
 
 
-        def eq_mct_ns_rule(model, i):
-            return sum(model.DirF[i]*model.F[c] for c in lin_mct[i]) <= \
-                model.Mct[i, 'ns']
+                elif p == 'GUA':
+                    return ((sum(model.F[c] for c in lin_mct['GUAHON'])) +
+                            (sum(model.F[c] for c in lin_mct['GUAELS']))) <= model.Imp[p, 'e', Mes]/100
 
 
-        model.eq_mct_ns = pe.Constraint(model.i, rule=eq_mct_ns_rule)
+                elif p == 'HON':  # Maxima importacion de Honduras
+                    return (-(sum(model.F[c] for c in lin_mct['ELSHON'])) -
+                            (sum(model.F[c] for c in lin_mct['GUAHON'])) +
+                            (sum(model.F[c] for c in lin_mct['HONNIC']))) <= model.Imp[p, 'e', Mes]/100
 
 
-        def eq_mct_sn_rule(model, i):
-            return sum(model.DirF[i]*model.F[c] for c in lin_mct[i]) >= \
-                -model.Mct[i, 'sn']
+                elif p == 'NIC':  # Maxima exportacion de Nicaragua
+                    return ((sum(model.F[c] for c in lin_mct['NICCRI'])) -
+                            (sum(model.F[c] for c in lin_mct['HONNIC']))) <= model.Imp[p, 'e', Mes]/100
 
 
-        model.eq_mct_sn = pe.Constraint(model.i, rule=eq_mct_sn_rule)
+                elif p == 'CR':  # Maxima exportacion de Costa Rica
+                    return (-((sum(model.F[c] for c in lin_mct['NICCRI'])) +
+                              (sum(model.F[c] for c in lin_mct['CRIPAN'])))) <= model.Imp[p, 'e', Mes]/100
 
 
-        model.dual = pe.Suffix(direction=pe.Suffix.IMPORT)
+                elif p == 'PAN':
+                    return sum(model.F[c] for c in lin_mct['CRIPAN']) <= model.Imp[p, 'e', Mes]/100
+            model.eq_i = pe.Constraint(model.p, rule=eq_imp_i_rule)
 
 
-        model_logger.info("Construcción del modelo terminada.")
+            def eq_imp_e_rule(model, p):
+                if p == 'ES':  # Maxima exportacion de El Salvador
+                    return ((sum(model.F[c] for c in lin_mct['ELSHON'])) -
+                            (sum(model.F[c] for c in lin_mct['GUAELS']))) >= - model.Imp[p, 'i', Mes]/100
 
 
-        filename = path.basename(self.file).split('.')[0]
-        filepath = path.dirname(self.file)
+                elif p == 'GUA':
+                    return ((sum(model.F[c] for c in lin_mct['GUAHON'])) +
+                            (sum(model.F[c] for c in lin_mct['GUAELS']))) >= - model.Imp[p, 'i', Mes]/100
 
 
-        try:
-            model_logger.info("Enviando modelo algebraico al solver")
-            opt = SolverFactory(
-                'ipopt'
-            )
+                elif p == 'HON':  # Maxima importacion de Honduras
+                    return (-(sum(model.F[c] for c in lin_mct['ELSHON'])) -
+                            (sum(model.F[c] for c in lin_mct['GUAHON'])) +
+                            (sum(model.F[c] for c in lin_mct['HONNIC']))) >= - model.Imp[p, 'i', Mes]/100
 
 
-            model_logger.info("Buscando una solución optima al problema")
-            result = opt.solve(
-                model, tee=self.tee,
-                logfile=f"log/solver_{filename}.log")
+                elif p == 'NIC':  # Maxima exportacion de Nicaragua
+                    return ((sum(model.F[c] for c in lin_mct['NICCRI'])) -
+                            (sum(model.F[c] for c in lin_mct['HONNIC']))) >= - model.Imp[p, 'i', Mes]/100
 
 
-            model.solutions.store_to(result)
-            result.write(
-                filename=f"{APPDIRS['DATA']}/results_{filename}.json",
-                format='json')
-            model_logger.info("Solucion encontrada")
+                elif p == 'CR':  # Maxima exportacion de Costa Rica
+                    return (-((sum(model.F[c] for c in lin_mct['NICCRI'])) +
+                              (sum(model.F[c] for c in lin_mct['CRIPAN'])))) >= - model.Imp[p, 'i', Mes]/100
 
 
-        except Exception as e:
-            model_logger.error("No se ejecutó el problema.")
-            model_logger.critical("Error: {}".format(e))
-            return
+                elif p == 'PAN':
+                    return sum(model.F[c] for c in lin_mct['CRIPAN']) >= - model.Imp[p, 'i', Mes]/100
+            model.eq_e = pe.Constraint(model.p, rule=eq_imp_e_rule)
 
 
-        # Cálculo de Precios Nodales
-        # =============================================================================
-        model_logger.info("Calculando Precios Nodales")
+            model.dual = pe.Suffix(direction=pe.Suffix.IMPORT)
 
 
-        Sigma = zeros(nbr)
-        for c in model.c:
-            Sigma[c] = model.dual[model.eq_Balance[c]]
+            model_logger.info("Construcción del modelo terminada.")
 
 
-        Lambda = model.dual[model.eq_perdidas_base]
+            filename = path.basename(self.file).split('.')[0]
+            filepath = path.dirname(self.file)
 
 
-        PON = (H.T @ Sigma) + Lambda
+            try:
+                model_logger.info("Enviando modelo algebraico al solver")
+                opt = SolverFactory(
+                    'ipopt'
+                )
 
 
-        # Cálculo de Pagos por Derechos Firmes
-        # =============================================================================
-        model_logger.info("Calculando Pagos Asignados por Derechos Firmes")
+                model_logger.info("Buscando una solución optima al problema")
+                result = opt.solve(
+                    model, tee=self.tee,
+                    logfile=f"log/solver_{filename}.log")
 
 
-        alpha = array(list(model.alpha_k.get_values().values()))
-        psi = array(list(model.gamma_k.get_values().values()))
+                model.solutions.store_to(result)
+                result.write(
+                    filename=f"{APPDIRS['DATA']}/results_{filename}.json",
+                    format='json')
+                model_logger.info("Solucion encontrada")
 
 
-        PDF_k = zeros(nof)
+            except Exception as e:
+                model_logger.error("No se ejecutó el problema.")
+                model_logger.critical("Error: {}".format(e))
+                return
 
 
-        for i in range(0, nof):
-            PDF_k[i] = -PON.T @ (alpha[i]*t[:, i] + psi[i]*vitx[:, i])
+            # Cálculo de Precios Nodales
+            # =============================================================================
+            model_logger.info("Calculando Precios Nodales")
 
 
-        # Construcción de array flujos en interconexiones
-        # =============================================================================
+            Sigma = zeros(nbr)
+            for c in model.c:
+                Sigma[c] = model.dual[model.eq_Balance[c]]
 
 
-        intercon = {}
+            Lambda = model.dual[model.eq_perdidas_base]
 
 
-        for i in model.i:
-            intercon[i] = [pe.value(model.eq_mct_sn[i].lower),
-                           pe.value(model.eq_mct_ns[i].body),
-                           pe.value(model.eq_mct_ns[i].upper)]
+            PON = (H.T @ Sigma) + Lambda
 
 
-        flujos_inter = pd.DataFrame.from_dict(intercon)
-        flujos_inter = flujos_inter * 100
+            # Cálculo de Pagos por Derechos Firmes
+            # =============================================================================
+            model_logger.info("Calculando Pagos Asignados por Derechos Firmes")
 
 
-        # Construcción de array para grabar
-        # =============================================================================
-        # filename = path.basename(self.file).split('.')
-        # filepath = path.dirname(self.file)
+            alpha = array(list(model.alpha_k.get_values().values()))
+            psi = array(list(model.gamma_k.get_values().values()))
 
 
-        model_logger.info(
-            "Escribiendo resultados en carpeta {0}".format(filepath))
+            PDF_k = zeros(nof)
 
 
-        # Resultados de Asignación
+            for i in range(0, nof):
+                PDF_k[i] = -PON.T @ (alpha[i]*t[:, i] + psi[i]*vitx[:, i])
 
 
-        resultado = of.copy()
+            # Construcción de array flujos en interconexiones
+            # =============================================================================
 
 
-        resultado['alpha'] = alpha
-        resultado['gamma'] = psi
-        resultado['MW_asign'] = resultado['MWo'] * resultado['alpha']
-        resultado['per_asign'] = resultado['per'] * resultado['gamma']
-        resultado['monto_asign'] = PDF_k.round(2)
-        resultado['precio_mw'] = resultado['monto_asign'] / \
-            (resultado['MW_asign'] * 24 * 31)  # Se toman meses de 31 días
+            intercon = {}
 
 
-        resultado.to_pickle(
-            path=f'{APPDIRS["DATA"]}/asignaciones_{filename}.dat')
+            for i in model.i:
+                intercon[i] = [pe.value(model.eq_mct_sn[i].lower),
+                               pe.value(model.eq_mct_ns[i].body),
+                               pe.value(model.eq_mct_ns[i].upper)]
 
 
-        # Flujos de Potencia
+            flujos_inter = pd.DataFrame.from_dict(intercon)
+            flujos_inter = flujos_inter * 100
 
 
-        flujos = net.copy()
-        flujos = flujos.drop(['x', 'r', 'max', 'min'], axis=1)
-        f = array(list(model.F.get_values().values()))
-        flujos['linea'] = brnames
-        flujos['flujo'] = f
-        flujos['perdidas'] = array(list(model.PL.get_values().values()))
-        flujos['sigma'] = Sigma
+            intercon_pais = {}
 
 
-        flujos.to_pickle(
-            path=f'{APPDIRS["DATA"]}/flujos_{filename}.dat')
+            for p in model.p:
+                intercon_pais[p] = [pe.value(model.eq_e[p].lower),
+                                    pe.value(model.eq_i[p].body),
+                                    pe.value(model.eq_i[p].upper)]
 
 
-        # Precios por Nodo
+            flujos_paises = pd.DataFrame.from_dict(intercon_pais)
+            flujos_paises = flujos_paises * 100
+
+            # Construcción de array para grabar
+            # =============================================================================
+            # filename = path.basename(self.file).split('.')
+            # filepath = path.dirname(self.file)
+
+            model_logger.info(
+                "Escribiendo resultados en carpeta {0}".format(filepath))
+
+            # Resultados de Asignación
 
 
-        pon = bus.copy()
-        pon['PON'] = PON
+            resultado = of.copy()
 
 
-        pon.to_pickle(
-            path=f'{APPDIRS["DATA"]}/pon_{filename}.dat')
+            resultado['alpha'] = alpha
+            resultado['gamma'] = psi
+            resultado['MW_asign'] = resultado['MWo'] * resultado['alpha']
+            resultado['per_asign'] = resultado['per'] * resultado['gamma']
+            resultado['monto_asign'] = PDF_k.round(2)
+            resultado['precio_mw'] = resultado['monto_asign'] / \
+                (resultado['MW_asign'] * 24 * 31)  # Se toman meses de 31 días
 
 
-        flujos_inter.to_pickle(
-            path=f'{APPDIRS["DATA"]}/flujos_inter_{filename}.dat')
+            resultado.to_pickle(
+                path=f'{APPDIRS["DATA"]}/asignaciones_{filename}.dat')
 
 
-        # Grabar en csv
-        # =================================================================================
-        csv_path = filepath
-        model_logger.info("Escribiendo archivo de asignaciones")
-        resultado.to_csv(
-            path.join(csv_path,
-                      filename + '_asignacion.csv'), sep=',', index=False)
+            # Flujos de Potencia
+
+            flujos = net.copy()
+            flujos = flujos.drop(['x', 'r', 'max', 'min'], axis=1)
+            f = array(list(model.F.get_values().values()))
+            flujos['linea'] = brnames
+            flujos['flujo'] = f
+            flujos['perdidas'] = array(list(model.PL.get_values().values()))
+            flujos['sigma'] = Sigma
+
+            flujos.to_pickle(
+                path=f'{APPDIRS["DATA"]}/flujos_{filename}.dat')
+
+            # Precios por Nodo
+
+            pon = bus.copy()
+            pon['PON'] = PON
+
+            pon.to_pickle(
+                path=f'{APPDIRS["DATA"]}/pon_{filename}.dat')
+
+            flujos_inter.to_pickle(
+                path=f'{APPDIRS["DATA"]}/flujos_inter_{filename}.dat')
 
 
-        model_logger.info("Escribiendo archivo de flujos de potencia")
-        flujos.to_csv(
-            path.join(csv_path,
-                      filename + '_flujos.csv'), sep=',', index=False)
+            flujos_paises.to_pickle(
+                path=f'{APPDIRS["DATA"]}/flujos_paises_{filename}.dat')
 
 
-        model_logger.info("Escribiendo archivo de flujos de precios")
-        pon.to_csv(
-            path.join(csv_path,
-                      filename + '_pon.csv'), sep=',', index=False)
+            picklefile = filename
 
 
-        model_logger.info(
-            "Escribiendo archivo de flujos de potencia entre areas de control")
-        flujos_inter.to_csv(
-            path.join(csv_path,
-                      filename + '_flujos_inter.csv'), sep=',', index=False)
+            # Grabar en excel
+            # ================================================================================
+            model_logger.info("Escribiendo archivo de resultados")
+            filename = path.basename(self.file).split('.')
+            filepath = path.dirname(self.file)
+            new_filename = filename[0] + \
+                '_results_{}.'.format(str(Mes))+filename[1]
+            new_file = path.join(filepath, new_filename)
+            writer = ExcelWriter(new_file)
+            resultado.to_excel(writer, sheet_name='MW Asignacion',
+                               index=False, header=True)
+            flujos.to_excel(writer, sheet_name='Flujos',
+                            index=False, header=True)
+            flujos_inter.to_excel(
+                writer, sheet_name='Flujos inter', index=False, header=True)
+            flujos_paises.to_excel(
+                writer, sheet_name='IMP-EXP TOT', index=False, header=True)
+            pon.to_excel(writer, sheet_name='pon', index=False, header=True)
+            writer.save()
+
+            # # Validacion de flujos
+            # # =================================================================================
+
+            validar_flujos(picklefile, mctp, Mes)
+
+            # # Grabar en csv
+            # # =================================================================================
+            # csv_path = filepath
+            # model_logger.info("Escribiendo archivo de asignaciones")
+            # resultado.to_csv(
+            #     path.join(csv_path,
+            #               filename + '_asignacion.csv'), sep=',', index=False)
+
+            # model_logger.info("Escribiendo archivo de flujos de potencia")
+            # flujos.to_csv(
+            #     path.join(csv_path,
+            #               filename + '_flujos.csv'), sep=',', index=False)
+
+            # model_logger.info("Escribiendo archivo de flujos de precios")
+            # pon.to_csv(
+            #     path.join(csv_path,
+            #               filename + '_pon.csv'), sep=',', index=False)
+
+            # model_logger.info(
+            #     "Escribiendo archivo de flujos de potencia entre areas de control")
+            # flujos_inter.to_csv(
+            #     path.join(csv_path,
+            #               filename + '_flujos_inter.csv'), sep=',', index=False)

+ 562 - 0
simsdt/model_12meses.py

@@ -0,0 +1,562 @@
+# -*- coding: utf-8 -*-
+"""
+Modulo principal para ejecutar el modelo de subasta
+"""
+
+from os import path
+
+import pandas as pd
+import pyomo.environ as pe
+from numpy import array, zeros
+from pandas import DataFrame, ExcelWriter
+from pyomo.environ import SolverFactory
+from pyomo.kernel import value
+
+from mct.makeEXP import linexp, readexp
+from mct.makeMCT import linmct, readmct, set_dir_flujo
+from ofertas.readBids import *
+from red.create import branchnames, setbranch, setbus
+from red.makeBdc import makeBdc
+from red.makePTDF import makePTDF
+from red.read import excel2net
+from utils.arr2dict import arr2dict
+from utils.idx_brch import RT_MAX, RT_MIN, R
+
+
+def setmodel(file, ver, tee):
+    if ver:
+        print("{:=^100}".format(""))
+        print("{:^100}".format(" Modelo de Subasta de Derechos Firmes "))
+        print("{:^100}".format(" Mercados Eléctricos de Centroamérica (c) 2018 "))
+        print("{:=^100}".format(""))
+
+    # ============================================================================
+    # Importación de datos desde archivo Excel
+    # ============================================================================
+
+        print("Inicio del Script de Subasta")
+        print("Leyendo información de red...")
+
+    net = excel2net(file)
+
+    if ver:
+        print("Leyendo información de ofertas y derechos firmes existentes...")
+
+    ex_t = readexistentes(file)
+    of = readofertas(file)
+    nof = of.shape[0]
+
+    # ============================================================================
+    # Construcción de vectores y matrices para los SETS y PARAMETERS
+    # ============================================================================
+    if ver:
+        print("Creando información de buses y líneas")
+    # Datos de Red
+    bus = setbus(net)
+    branch = setbranch(net, bus)
+
+    nb = bus.shape[0]
+    nbr = branch.shape[0]
+
+    if ver:
+        print("Se han cargado {0} buses y {1} líneas".format(nb, nbr))
+        print("Leyendo información de Resistencia de líneas")
+
+    brnames = branchnames(bus, branch)
+    r = branch[:, R]
+
+    if ver:
+        # Datos de límites superior e inferior asociados a las lineas
+        print("Obteniendo datos de límites superior e inferior de líneas...")
+    bu = branch[:, RT_MAX]/100
+    bl = branch[:, RT_MIN]/100
+
+    # Lineas para límites de MCT
+    lin_mct = linmct(brnames)
+    mct = readmct(file)
+    print(mct)
+    dirf = set_dir_flujo()
+
+    # Max impo/rxp
+    lin_exp = linexp(brnames)
+    exp = readexp(file)
+
+    if ver:
+        print("Cálculando la matriz H")
+    # Cálculo de la matriz H
+    H = makePTDF(bus, branch)
+
+    if ver:
+        print("Cálculando la matriz de Incidencia")
+    # Matriz de Incidencia
+    _, _, A = makeBdc(bus, branch)
+    inc = A.toarray()**2
+
+    if ver:
+        print("Creando vectores de Ofertas de Derechos firmes")
+    # Datos de las ofertas de Derechos Firmes
+    c = of.oferta.values
+    cper = of.cper.values
+    perk = of.per.values/100
+    vit = setVIT(bus, of)/100
+    vrt = setVRT(bus, of)/100
+    vitx = setVITX(bus, of)/100
+    t = setT(vit, vrt)
+
+    # Aqui tiene que empezar el FOR
+    for Mes in range(4, 6):
+        # Filtra las ofertas existentes por Mes
+        ex = ex_t[ex_t.mes_vig.isin([Mes])].copy()
+        ex.reset_index(drop=True, inplace=True)  # Reset de indices del df
+        # Quitamos la columna de Mes para usar la funciones
+        ex.drop(['mes_vig'], axis='columns', inplace=True)
+
+        nex = ex.shape[0]
+
+        if ver:
+            print("Creando Vectores de Derechos Firmes existentes")
+        # Datos de los Derechos Firmes Existentes
+        vite = setVITE(bus, ex)/100
+        vrte = setVRTE(bus, ex)/100
+        vitex = setVITEX(bus, ex)/100
+        te = setTE(vite, vrte)
+
+        # ============================================================================
+        # Modelo de optimización subasta de derechos Firmes
+        # ============================================================================
+
+        if ver:
+            print("Inicio del problema de Optimización")
+        # Inicio del modelo de optimización
+
+        model = pe.ConcreteModel()
+
+        # SETS
+        if ver:
+            print("Creando SETS")
+        model.c = pe.Set(initialize=range(0, nbr))   # Número de circuitos
+        model.n = pe.Set(initialize=range(0, nb))    # Número de nodos
+        model.o = pe.Set(initialize=range(0, nex))   # Número de DF existentes
+        model.k = pe.Set(initialize=range(0, nof))   # Número de Ofertas DF
+        model.i = pe.Set(initialize=lin_mct.keys())  # Interconexiones
+        model.p = pe.Set(initialize=lin_exp.keys())  # Paises
+        # Sentidos de interconexiones
+        model.s = pe.Set(initialize=['sn', 'ns'])
+        model.trans = pe.Set(initialize=['i', 'e'])
+        model.m = pe.Set(initialize=range(1, 12))
+
+        # PARAMETERS
+        if ver:
+            print("Creando PARAMETROS")
+        # Ofertas derechos firmes
+            print("Parametros de Ofertas de Derechos Firmes")
+        model.C = pe.Param(model.k, initialize=dict(enumerate(c)))
+        model.Cper = pe.Param(model.k, initialize=dict(enumerate(cper)))
+        model.Perk = pe.Param(model.k, initialize=dict(enumerate(perk)))
+
+        # Parametros de la red
+        if ver:
+            print("Parametros de Red")
+        model.Bu = pe.Param(model.c, initialize=dict(enumerate(bu)))
+        model.Bl = pe.Param(model.c, initialize=dict(enumerate(bl)))
+        model.R = pe.Param(model.c, initialize=dict(enumerate(r)))
+        model.Inc = pe.Param(model.c, model.n, initialize=arr2dict(inc))
+
+        # elemento H[c,n]
+        if ver:
+            print("Parametros de Matriz H")
+        model.He = pe.Param(model.c, model.n, initialize=arr2dict(H))
+
+        if ver:
+            print("Parametros de Derechos Firmes Existentes")
+        # Vector de inyecciones df existentes
+        model.VITE = pe.Param(model.n, model.o, initialize=arr2dict(vite))
+        # Vector de retiros df existentes
+        model.VRTE = pe.Param(model.n, model.o, initialize=arr2dict(vrte))
+        # Vector de perididas df existentes
+        model.VITEX = pe.Param(model.n, model.o, initialize=arr2dict(vitex))
+        # DF existentes
+        model.TE = pe.Param(model.n, model.o, initialize=arr2dict(te))
+
+        if ver:
+            print("Parametros de Inyecciones y Retiros de Ofertas")
+        # Vector inyecciones ofertas de compra df
+        model.VIT = pe.Param(model.n, model.k, initialize=arr2dict(vit))
+        # Vector retiros ofertas de compra df
+        model.VRT = pe.Param(model.n, model.k, initialize=arr2dict(vrt))
+        # Vector inyecciones perdidas oferta de compra df
+        model.VITX = pe.Param(model.n, model.k, initialize=arr2dict(vitx))
+        # Ofertas de compora DF
+        model.T = pe.Param(model.n, model.k, initialize=arr2dict(t))
+
+        if ver:
+            print("Parametros de Limites de flujos en las líneas")
+
+        # Lim. Superior flujos asociados a linea c
+        def bfu_param(model, c):
+            return model.Bu[c] - sum(max(0, sum(model.He[c, n]*model.TE[n, o]
+                                                for n in model.n)) for o in model.o)
+
+        model.BFu = pe.Param(model.c, initialize=bfu_param)
+
+        # LIm. Inferior flujos asociados a linea c
+        def bfl_param(model, c):
+            return model.Bl[c] - sum(max(0, -sum(model.He[c, n]*model.TE[n, o] for n in model.n)) for o in model.o)
+
+        model.BFl = pe.Param(model.c, initialize=bfl_param)
+
+        # Máximas Capacidades de Trasferencia
+        model.Mct = pe.Param(model.i, model.s, model.m,
+                             initialize=mct.mct.to_dict())
+        model.DirF = pe.Param(model.i, initialize=dirf)
+
+        # Maxima Imp/Exp
+        model.Imp = pe.Param(model.p, model.trans, model.m,
+                             initialize=exp.MW.to_dict())
+
+        # VARIABLES
+        if ver:
+            print("Creando VARIABLES")
+        # Variables primales
+
+        # Proporcion del DF de compra asignado en la subasta > 0
+        model.alpha_k = pe.Var(
+            model.k, within=pe.NonNegativeReals, bounds=(0, 1))
+        # Porcentaje de perdidas ligadas al DF de compra asignado en la subasta > 0
+        model.gamma_k = pe.Var(model.k, within=pe.NonNegativeReals)
+
+        # Flujos
+
+        model.F = pe.Var(model.c)
+        model.PL = pe.Var(model.c)
+        model.Per = pe.Var(model.n)
+        model.F_k = pe.Var(model.c, model.k)
+        model.Fp_k = pe.Var(model.c, model.k, within=pe.NonNegativeReals)
+        model.Fp = pe.Var(model.c, within=pe.NonNegativeReals)
+        model.Fn_k = pe.Var(model.c, model.k, within=pe.NonNegativeReals)
+        model.Fn = pe.Var(model.c, within=pe.NonNegativeReals)
+
+        # EQUATIONS
+        if ver:
+            print("Creando ECUACIONES")
+        # Ecuación Objetivo
+        # =============================================================================
+        if ver:
+            print("Ecuación de Función Objetivo Max Z")
+
+        def eq_Z(model):
+            return sum(model.alpha_k[k]*model.C[k] - model.gamma_k[k]*model.Cper[k] for k in model.k)
+
+        model.Z = pe.Objective(rule=eq_Z, sense=pe.maximize)
+
+        # Restricciones
+        # =============================================================================
+        if ver:
+            print("Restricciones del Modelo de Optimización")
+            print("Límites de Gamma")
+
+        def eq_gamma_k_rule(model, k):
+            return model.gamma_k[k] <= model.alpha_k[k]
+
+        model.eq_gamma_k = pe.Constraint(model.k, rule=eq_gamma_k_rule)
+
+        # Factibilidad de derechos firmes
+        if ver:
+            print("Factibilidad de derechos Firmes")
+
+        def eq_F_k_rule(model, c, k):
+            return model.F_k[c, k] == model.alpha_k[k]*sum(model.He[c, n]*model.T[n, k] for n in model.n)
+
+        model.eq_F_k = pe.Constraint(model.c, model.k, rule=eq_F_k_rule)
+
+        # Flujos positivos
+        if ver:
+            print("Flujos positivos")
+
+        def eq_Fp_k_rule(model, c, k):
+            return model.Fp_k[c, k] >= model.F_k[c, k]
+
+        model.eq_Fp_k = pe.Constraint(model.c, model.k, rule=eq_Fp_k_rule)
+
+        def eq_Fp_rule(model, c):
+            return model.Fp[c] == sum(model.Fp_k[c, k] for k in model.k)
+
+        model.eq_Fp = pe.Constraint(model.c, rule=eq_Fp_rule)
+
+        def eq_Fpl_rule(model, c):
+            return sum(model.Fp_k[c, k] for k in model.k) <= model.BFu[c]
+
+        model.eq_Fpl = pe.Constraint(model.c, rule=eq_Fpl_rule)
+
+        # Flujos negativos
+        if ver:
+            print("Flujos negativos")
+
+        def eq_Fn_k_rule(model, c, k):
+            return model.Fn_k[c, k] >= -model.F_k[c, k]
+
+        model.eq_Fn_k = pe.Constraint(model.c, model.k, rule=eq_Fn_k_rule)
+
+        def eq_Fn_rule(model, c):
+            return model.Fn[c] == sum(model.Fn_k[c, k] for k in model.k)
+
+        model.eq_Fn = pe.Constraint(model.c, rule=eq_Fn_rule)
+
+        def eq_Fnl_rule(model, c):
+            return sum(model.Fn_k[c, k] for k in model.k) <= model.BFl[c]
+
+        model.eq_Fnl = pe.Constraint(model.c, rule=eq_Fnl_rule)
+
+        # Suficiencia Financiera
+        if ver:
+            print("Suficiencia Financiera")
+
+        def eq_sf1_rule(model, c):
+            return model.F[c] <= model.Bu[c]
+
+        model.eq_sf1 = pe.Constraint(model.c, rule=eq_sf1_rule)
+
+        def eq_sf2_rule(model, c):
+            return model.F[c] >= -model.Bl[c]
+
+        model.eq_sf2 = pe.Constraint(model.c, rule=eq_sf2_rule)
+
+        # Balance de Pérdidas
+        if ver:
+            print("Balance de Pérdidas")
+
+        def eq_PL_rule(model, c):
+            return model.PL[c] == (model.R[c])*(model.F[c]*model.F[c])
+
+        model.eq_PL = pe.Constraint(model.c, rule=eq_PL_rule)
+
+        def eq_Per_rule(model, n):
+            return model.Per[n] == sum(model.Inc[c, n]*(model.PL[c]/2) for c in model.c)
+
+        model.eq_Per = pe.Constraint(model.n, rule=eq_Per_rule)
+
+        # Balance de Flujos
+        if ver:
+            print("Balance de Flujos")
+
+        def eq_Balance_rule(model, c):
+            return model.F[c] == sum(model.He[c, n]*(
+                sum(model.alpha_k[k]*model.T[n, k] for k in model.k) +
+                sum(model.TE[n, o] for o in model.o) +
+                sum(model.gamma_k[k]*model.VITX[n, k] for k in model.k) +
+                sum(model.VITEX[n, o]for o in model.o) -
+                model.Per[n]) for n in model.n)
+
+        model.eq_Balance = pe.Constraint(model.c, rule=eq_Balance_rule)
+
+        # Perdidas en estado base
+        if ver:
+            print("Perdidas en estado Base")
+
+        def eq_perdidas_base_rule(model):
+            return sum(model.PL[c] for c in model.c) == sum(
+                sum(model.gamma_k[k]*model.VITX[n, k] for k in model.k) +
+                sum(model.VITEX[n, o] for o in model.o) for n in model.n)
+
+        model.eq_perdidas_base = pe.Constraint(rule=eq_perdidas_base_rule)
+
+        # Máximas capacidades de trasferencia entre áreas de control
+        if ver:
+            print("Máxima Capacidad de Trasnferencia entre áreas de control")
+
+        def eq_mct_ns_rule(model, i):
+
+            return sum(model.DirF[i]*model.F[c] for c in lin_mct[i]) <= model.Mct[i, 'ns', Mes]/100
+
+        model.eq_mct_ns = pe.Constraint(model.i, rule=eq_mct_ns_rule)
+
+        def eq_mct_sn_rule(model, i):
+            return sum(model.DirF[i]*model.F[c] for c in lin_mct[i]) >= -model.Mct[i, 'sn', Mes]/100
+        model.eq_mct_sn = pe.Constraint(model.i, rule=eq_mct_sn_rule)
+
+        # Maxima importacion/exportacion
+        def eq_imp_i_rule(model, p):
+            if p == 'ES':  # Maxima exportacion de El Salvador
+                return ((sum(model.F[c] for c in lin_mct['ELSHON'])) -
+                        (sum(model.F[c] for c in lin_mct['GUAELS']))) <= model.Imp[p, 'e', Mes]/100
+
+            elif p == 'GUA':
+                return ((sum(model.F[c] for c in lin_mct['GUAHON'])) +
+                        (sum(model.F[c] for c in lin_mct['GUAELS']))) <= model.Imp[p, 'e', Mes]/100
+
+            elif p == 'HON':  # Maxima importacion de Honduras
+                return (-(sum(model.F[c] for c in lin_mct['ELSHON'])) -
+                        (sum(model.F[c] for c in lin_mct['GUAHON'])) +
+                        (sum(model.F[c] for c in lin_mct['HONNIC']))) <= model.Imp[p, 'e', Mes]/100
+
+            elif p == 'NIC':  # Maxima exportacion de Nicaragua
+                return ((sum(model.F[c] for c in lin_mct['NICCRI'])) -
+                        (sum(model.F[c] for c in lin_mct['HONNIC']))) <= model.Imp[p, 'e', Mes]/100
+
+            elif p == 'CR':  # Maxima exportacion de Costa Rica
+                return (-((sum(model.F[c] for c in lin_mct['NICCRI'])) +
+                          (sum(model.F[c] for c in lin_mct['CRIPAN'])))) <= model.Imp[p, 'e', Mes]/100
+
+            elif p == 'PAN':
+                return sum(model.F[c] for c in lin_mct['CRIPAN']) <= model.Imp[p, 'e', Mes]/100
+        model.eq_i = pe.Constraint(model.p, rule=eq_imp_i_rule)
+
+        def eq_imp_e_rule(model, p):
+            if p == 'ES':  # Maxima exportacion de El Salvador
+                return ((sum(model.F[c] for c in lin_mct['ELSHON'])) -
+                        (sum(model.F[c] for c in lin_mct['GUAELS']))) >= - model.Imp[p, 'i', Mes]/100
+
+            elif p == 'GUA':
+                return ((sum(model.F[c] for c in lin_mct['GUAHON'])) +
+                        (sum(model.F[c] for c in lin_mct['GUAELS']))) >= - model.Imp[p, 'i', Mes]/100
+
+            elif p == 'HON':  # Maxima importacion de Honduras
+                return (-(sum(model.F[c] for c in lin_mct['ELSHON'])) -
+                        (sum(model.F[c] for c in lin_mct['GUAHON'])) +
+                        (sum(model.F[c] for c in lin_mct['HONNIC']))) >= - model.Imp[p, 'i', Mes]/100
+
+            elif p == 'NIC':  # Maxima exportacion de Nicaragua
+                return ((sum(model.F[c] for c in lin_mct['NICCRI'])) -
+                        (sum(model.F[c] for c in lin_mct['HONNIC']))) >= - model.Imp[p, 'i', Mes]/100
+
+            elif p == 'CR':  # Maxima exportacion de Costa Rica
+                return (-((sum(model.F[c] for c in lin_mct['NICCRI'])) +
+                          (sum(model.F[c] for c in lin_mct['CRIPAN'])))) >= - model.Imp[p, 'i', Mes]/100
+
+            elif p == 'PAN':
+                return sum(model.F[c] for c in lin_mct['CRIPAN']) >= - model.Imp[p, 'i', Mes]/100
+        model.eq_e = pe.Constraint(model.p, rule=eq_imp_e_rule)
+
+        model.dual = pe.Suffix(direction=pe.Suffix.IMPORT)
+        if ver:
+            print("Construcción del modelo terminada.")
+
+        try:
+            opt = SolverFactory(
+                'ipopt'
+            )
+
+            result = opt.solve(model, tee=ver or tee)
+            model.solutions.store_to(result)
+
+        except Exception as e:
+            print("No se ejecutó el problema.")
+            print("Error: ", e)
+            return
+
+        # Cálculo de Precios Nodales
+        # =============================================================================
+        print("Calculando Precios Nodales")
+
+        Sigma = zeros(nbr)
+        for c in model.c:
+            Sigma[c] = model.dual[model.eq_Balance[c]]
+
+        #Lambda = model.dual[model.eq_perdidas_base]
+
+        PON = (H.T @ Sigma)  # + Lambda
+
+        # Cálculo de Pagos por Derechos Firmes
+        # =============================================================================
+        print("Calculando Pagos Asignados por Derechos Firmes")
+
+        alpha = array(list(model.alpha_k.get_values().values()))
+        psi = array(list(model.gamma_k.get_values().values()))
+
+        PDF_k = zeros(nof)
+
+        for i in range(0, nof):
+            PDF_k[i] = -PON.T @ (alpha[i]*t[:, i] + psi[i]*vitx[:, i])
+
+        # Construcción de array flujos en interconexiones
+        # =============================================================================
+
+        intercon = {}
+
+        for i in model.i:
+            intercon[i] = [pe.value(model.eq_mct_sn[i].lower),
+                           pe.value(model.eq_mct_ns[i].body),
+                           pe.value(model.eq_mct_ns[i].upper)]
+
+        flujos_inter = pd.DataFrame.from_dict(intercon)
+        flujos_inter = flujos_inter * 100
+
+        intercon_pais = {}
+
+        for p in model.p:
+            intercon_pais[p] = [pe.value(model.eq_e[p].lower),
+                                pe.value(model.eq_i[p].body),
+                                pe.value(model.eq_i[p].upper)]
+
+        flujos_paises = pd.DataFrame.from_dict(intercon_pais)
+        flujos_paises = flujos_paises * 100
+
+        # Construcción de array para grabar
+        # =============================================================================
+        filename = path.basename(file).split('.')
+        filepath = path.dirname(file)
+
+        print("Escribiendo resultados en carpeta {0}".format(filepath))
+
+        # Resultados de Asignación
+
+        resultado = of.copy()
+
+        resultado['alpha'] = alpha
+        resultado['gamma'] = psi
+        resultado['MW_asign'] = resultado['MWo'] * resultado['alpha']
+        resultado['per_asign'] = resultado['per'] * resultado['gamma']
+        resultado['monto_asign'] = PDF_k.round(2)
+        resultado['precio_mw'] = resultado['monto_asign'] / \
+            (resultado['MW_asign'] * 24 * 31)  # Se toman meses de 31 días
+
+        # Flujos de Potencia
+
+        flujos = net.copy()
+        flujos = flujos.drop(['x', 'r', 'max', 'min'], axis=1)
+        f = array(list(model.F.get_values().values()))
+        flujos['linea'] = brnames
+        flujos['flujo'] = f
+        flujos['perdidas'] = array(list(model.PL.get_values().values()))
+        flujos['sigma'] = Sigma
+
+        # Precios por Nodo
+
+        pon = bus.copy()
+        pon['PON'] = PON
+
+        # Grabar en excel
+        # ================================================================================
+        filename = path.basename(file).split('.')
+        filepath = path.dirname(file)
+        new_filename = filename[0]+'_results_{}.'.format(str(Mes))+filename[1]
+        new_file = path.join(filepath, new_filename)
+        writer = ExcelWriter(new_file)
+        resultado.to_excel(writer, sheet_name='MW Asignacion',
+                           index=False, header=True)
+        flujos.to_excel(writer, sheet_name='Flujos', index=False, header=True)
+        flujos_inter.to_excel(
+            writer, sheet_name='Flujos inter', index=False, header=True)
+        flujos_paises.to_excel(
+            writer, sheet_name='IMP-EXP TOT', index=False, header=True)
+        pon.to_excel(writer, sheet_name='pon', index=False, header=True)
+        writer.save()
+
+        # Grabar en csv
+        # =================================================================================
+        #csv_path = filepath
+        # resultado.to_csv(
+        #    path.join(csv_path, filename[0] + '_asignacion.csv'), sep=',', index=False)
+        # flujos.to_csv(
+        #    path.join(csv_path, filename[0] + '_flujos.csv'), sep=',', index=False)
+        # pon.to_csv(
+        #    path.join(csv_path, filename[0] + '_pon.csv'), sep=',', index=False)
+        # flujos_inter.to_csv(
+        #    path.join(csv_path, filename[0] + '_flujos_inter.csv'), sep=',', index=False)
+
+        print("{:=^100}".format(""))
+        print("{:^100}".format(" Script Finalizado "))
+        print("{:^100}".format(" Mercados Eléctricos de Centroamérica (c) 2018 "))
+        print("{:=^100}".format(""))
+
+        return 0

+ 3 - 2
simsdt/ofertas/readBids.py

@@ -14,7 +14,7 @@ def readexistentes(subasta_file):
     """Lee del archivo Excel la información de Derechos Firmes existente.
     """Lee del archivo Excel la información de Derechos Firmes existente.
 
 
     Retorna un DataFrame con las columnas siguientes:
     Retorna un DataFrame con las columnas siguientes:
-
+        0. mes_vig       : Mes de vigencia del DF
         1. cod_agente    : Código del Agente propietario del DF existente.
         1. cod_agente    : Código del Agente propietario del DF existente.
         2. tke           : identificador del DF existente
         2. tke           : identificador del DF existente
         3. bus_ie        : Nodo de inyección del DF existente
         3. bus_ie        : Nodo de inyección del DF existente
@@ -22,7 +22,8 @@ def readexistentes(subasta_file):
         5. MWe           : Potencia asignada al DF existente
         5. MWe           : Potencia asignada al DF existente
     """
     """
     exist = read_excel(subasta_file, sheet_name='existentes')
     exist = read_excel(subasta_file, sheet_name='existentes')
-    exist.columns = ['cod_agente', 'tke', 'bus_ie', 'bus_je', 'MWe', 'per']
+    exist.columns = ['mes_vig', 'cod_agente',
+                     'tke', 'bus_ie', 'bus_je', 'MWe', 'per']
 
 
     return exist
     return exist
 
 

+ 3 - 0
simsdt/prueba.py

@@ -0,0 +1,3 @@
+from runsdt import main
+
+main('subasta_A2101_abril_mayo.xlsx')

+ 2 - 2
simsdt/runsdt.py

@@ -10,13 +10,13 @@ from simsdt.model import ModeloSubasta
 run_logger = logging.getLogger('simsdt.run')
 run_logger = logging.getLogger('simsdt.run')
 
 
 
 
-def main(file, tee=False):
+def main(file, p_exec, all_year=True, tee=False):
     """Ejecuta la Simulación de Subastas de Derechos de Transmisión."""
     """Ejecuta la Simulación de Subastas de Derechos de Transmisión."""
     try:
     try:
         # Check if solver 'ipopt' is on path
         # Check if solver 'ipopt' is on path
         run_logger.info("Inicio de la ejecucion del modelo de subasta")
         run_logger.info("Inicio de la ejecucion del modelo de subasta")
 
 
-        modelo_subasta = ModeloSubasta(file, tee=tee)
+        modelo_subasta = ModeloSubasta(file, p_exec, all_year=True, tee=tee)
 
 
         modelo_subasta.setmodel()
         modelo_subasta.setmodel()
         # time.sleep(10)
         # time.sleep(10)

+ 1 - 1
simsdt/runtrhead.py

@@ -21,7 +21,7 @@ class RunsdtThread(threading.Thread):
 
 
     def run(self):
     def run(self):
         t = time.time()
         t = time.time()
-        runsdt.main(self.args)
+        runsdt.main(*self.args)
         elapsed_time = time.time() - t
         elapsed_time = time.time() - t
         et = time.strftime("%H:%M:%S", time.gmtime(elapsed_time))
         et = time.strftime("%H:%M:%S", time.gmtime(elapsed_time))
         logger.info('Tiempo de ejecución %s' % et)
         logger.info('Tiempo de ejecución %s' % et)

+ 1 - 2
simsdt/utils/excel_checker.py

@@ -1,11 +1,10 @@
 import xlrd
 import xlrd
-
 from common.exceptions import ExcelFileError
 from common.exceptions import ExcelFileError
 
 
 
 
 def check_excel_file(file):
 def check_excel_file(file):
 
 
-    sheets_names = ['oferta', 'existentes', 'mct', 'rtr']
+    sheets_names = ['oferta', 'existentes', 'mct', 'rtr', 'exp']
 
 
     try:
     try:
         xls = xlrd.open_workbook(file, on_demand=True)
         xls = xlrd.open_workbook(file, on_demand=True)

+ 7 - 7
ui/app.py

@@ -1,14 +1,14 @@
 import logging
 import logging
 import queue
 import queue
 import signal
 import signal
-import time
 from tkinter import HORIZONTAL, VERTICAL, messagebox, ttk
 from tkinter import HORIZONTAL, VERTICAL, messagebox, ttk
 
 
 from qhandler import QueueHandler
 from qhandler import QueueHandler
+
 from ui.console import ConsoleUi
 from ui.console import ConsoleUi
 from ui.forms import FormUi
 from ui.forms import FormUi
-from ui.results import ResultUi
-from ui.splash import Splash
+# from ui.results import ResultUi
+# from ui.splash import Splash
 from ui.status import StatusUi
 from ui.status import StatusUi
 
 
 logger = logging.getLogger('simsdt')
 logger = logging.getLogger('simsdt')
@@ -48,7 +48,7 @@ class App:
 
 
         self.queue_handler = QueueHandler(log_queue)
         self.queue_handler = QueueHandler(log_queue)
         formatter = logging.Formatter(
         formatter = logging.Formatter(
-            '%(asctime)s: %(message)s', datefmt='%Y-%m-%dT%H:%M:%S')
+            '%(asctime)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
         self.queue_handler.setFormatter(formatter)
         self.queue_handler.setFormatter(formatter)
         # self.queue_handler.setLevel(logging.INFO)
         # self.queue_handler.setLevel(logging.INFO)
         logger.addHandler(self.queue_handler)
         logger.addHandler(self.queue_handler)
@@ -63,7 +63,7 @@ class App:
                padx=10, pady=(0, 10))
                padx=10, pady=(0, 10))
 
 
         tab_exec = ttk.Frame(w)
         tab_exec = ttk.Frame(w)
-        tab_result = ttk.Frame(w)
+        # tab_result = ttk.Frame(w)
 
 
         # Create the panes and frames
         # Create the panes and frames
         vertical_pane = ttk.PanedWindow(
         vertical_pane = ttk.PanedWindow(
@@ -99,12 +99,12 @@ class App:
         self.console = ConsoleUi(console_frame, log_queue, self.queue_handler)
         self.console = ConsoleUi(console_frame, log_queue, self.queue_handler)
         self.status = StatusUi(status_frame, pbqueue)
         self.status = StatusUi(status_frame, pbqueue)
 
 
-        self.result = ResultUi(tab_result)
+        # self.result = ResultUi(tab_result)
 
 
         # setup tabs
         # setup tabs
 
 
         w.add(tab_exec, text='Ejecución')
         w.add(tab_exec, text='Ejecución')
-        w.add(tab_result, text='Resultados')
+        # w.add(tab_result, text='Resultados')
 
 
         # bindings
         # bindings
 
 

+ 71 - 5
ui/forms.py

@@ -3,13 +3,25 @@ import tkinter as tk
 from tkinter import E, W, filedialog, ttk
 from tkinter import E, W, filedialog, ttk
 
 
 from PIL import Image, ImageTk
 from PIL import Image, ImageTk
-
 from simsdt.runtrhead import RunsdtThread
 from simsdt.runtrhead import RunsdtThread
 from simsdt.utils.excel_checker import check_excel_file
 from simsdt.utils.excel_checker import check_excel_file
 from simsdt.utils.solver_checker import check_solver
 from simsdt.utils.solver_checker import check_solver
 
 
 main_logger = logging.getLogger('simsdt')
 main_logger = logging.getLogger('simsdt')
 
 
+meses = {1: {'mes': 'Enero', 'cb': None},
+         2: {'mes': 'Febrero', 'cb': None},
+         3: {'mes': 'Marzo', 'cb': None},
+         4: {'mes': 'Abril', 'cb': None},
+         5: {'mes': 'Mayo', 'cb': None},
+         6: {'mes': 'Junio', 'cb': None},
+         7: {'mes': 'Julio', 'cb': None},
+         8: {'mes': 'Agosto', 'cb': None},
+         9: {'mes': 'Septiembre', 'cb': None},
+         10: {'mes': 'Octubre', 'cb': None},
+         11: {'mes': 'Noviembre', 'cb': None},
+         12: {'mes': 'Diciembre', 'cb': None}}
+
 
 
 class FormUi:
 class FormUi:
 
 
@@ -18,10 +30,10 @@ class FormUi:
     def __init__(self, frame, q):
     def __init__(self, frame, q):
         self.frame = frame
         self.frame = frame
         self.q = q
         self.q = q
-        image = Image.open('img/icons/icons8-play-16.png')
+        image = Image.open('ui/img/icons/icons8-play-16.png')
         self.photo = ImageTk.PhotoImage(image)
         self.photo = ImageTk.PhotoImage(image)
 
 
-        opfile = Image.open('img/icons/icons8-abrir-carpeta-16.png')
+        opfile = Image.open('ui/img/icons/icons8-abrir-carpeta-16.png')
         self.opfile = ImageTk.PhotoImage(opfile)
         self.opfile = ImageTk.PhotoImage(opfile)
 
 
         # Add a text field for file path
         # Add a text field for file path
@@ -31,14 +43,48 @@ class FormUi:
         self.entry = ttk.Entry(self.frame, textvariable=self.file_path,
         self.entry = ttk.Entry(self.frame, textvariable=self.file_path,
                                width=50)
                                width=50)
         self.entry.grid(column=1, row=0, sticky=(W, E), pady=(5, 5))
         self.entry.grid(column=1, row=0, sticky=(W, E), pady=(5, 5))
+
         self.button = ttk.Button(
         self.button = ttk.Button(
             self.frame, image=self.opfile, compound='center',
             self.frame, image=self.opfile, compound='center',
             command=self.open_file_dialog, width=3)
             command=self.open_file_dialog, width=3)
         self.button.grid(column=2, row=0, sticky=W)
         self.button.grid(column=2, row=0, sticky=W)
+
+        self.all_year = tk.IntVar()
+        self.all_year_cb = ttk.Checkbutton(
+            self.frame, text="Ejecutar 12 meses", variable=self.all_year, command=self.chkbox_state)
+        self.all_year_cb.state(['selected'])
+        self.all_year.set(1)
+        self.all_year_cb.grid(column=1, row=1, sticky=W)
+
+        # # Intentando hacer checkboxes en vez de combobox
+        # m = []
+        # r = 2
+        # for (k, v) in meses.items():
+        #     for j in range(1):
+        #         if j == 0:
+        #             tk.Label(self.frame, text=v['mes']).grid(
+        #                 row=r, column=j, padx=5, pady=5)
+        #         else:
+        #             v['cb'] = ttk.Checkbutton(
+        #                 self.frame, variable=tk.IntVar())
+        #             v['cb'].state(['deselected'])
+        #             v['cb'].set(0)
+        #             v['cb'].grid(row=r+1, column=j+1, padx=5, pady=5)
+        #     r += 1
+
+        periodos = [*range(1, 13)]
+        ttk.Label(self.frame, text='Periodo:').grid(
+            column=0, row=2, sticky=W, pady=(5, 5), padx=(0, 10))
+        self.period_combo = ttk.Combobox(self.frame, values=periodos)
+        self.period_combo.current(0)
+        self.period_combo.set(1)
+        self.period_combo.configure(state='disabled')
+        self.period_combo.grid(column=1, row=2, sticky=W)
+
         self.button_run = ttk.Button(self.frame, image=self.photo,
         self.button_run = ttk.Button(self.frame, image=self.photo,
                                      compound="right", text='Ejecutar',
                                      compound="right", text='Ejecutar',
                                      command=self.run)
                                      command=self.run)
-        self.button_run.grid(column=1, row=1, sticky=W)
+        self.button_run.grid(column=1, row=15, sticky=W)
 
 
     def open_file_dialog(self):
     def open_file_dialog(self):
         # Open file dialog
         # Open file dialog
@@ -54,6 +100,14 @@ class FormUi:
             main_logger.info(f'Archivo seleccionado: {file}')
             main_logger.info(f'Archivo seleccionado: {file}')
             self.file_path.set(file)
             self.file_path.set(file)
 
 
+    def chkbox_state(self):
+        if self.all_year_cb.instate(['selected']):
+            self.period_combo.configure(state='disabled')
+            self.period_combo.current(0)
+            self.period_combo.set(12)
+        else:
+            self.period_combo.configure(state='normal')
+
     def run(self):
     def run(self):
         try:
         try:
 
 
@@ -64,10 +118,22 @@ class FormUi:
 
 
             check_solver()
             check_solver()
 
 
+            if not self.file_path.get():
+                return
+
+            inputfile = self.file_path.get()
+            all_year = self.all_year.get()
+            if all_year == 1:
+                all_year = True
+            else:
+                all_year = False
+
+            period = self.period_combo.get()
             self.button_run.configure(state='disabled')
             self.button_run.configure(state='disabled')
             main_logger.info('Ejecutando')
             main_logger.info('Ejecutando')
 
 
-            self.runsdt_thread = RunsdtThread(args=(self.file_path.get()))
+            self.runsdt_thread = RunsdtThread(
+                args=(inputfile, int(period), all_year))
             self.runsdt_thread.start()
             self.runsdt_thread.start()
 
 
             self.check_thread()
             self.check_thread()

BIN
ui/img/icons/icons8-abrir-carpeta-16.png


BIN
ui/img/icons/icons8-apoyo-16.png


BIN
ui/img/icons/icons8-archivo-16.png


BIN
ui/img/icons/icons8-bloquear-16.png


BIN
ui/img/icons/icons8-cancelar-16.png


BIN
ui/img/icons/icons8-cancelar-2-16.png


BIN
ui/img/icons/icons8-carpeta-16.png


BIN
ui/img/icons/icons8-casa-16.png


BIN
ui/img/icons/icons8-comprobado-16.png


BIN
ui/img/icons/icons8-desbloquear-16.png


BIN
ui/img/icons/icons8-documento-16.png


BIN
ui/img/icons/icons8-eliminar-16-2.png


BIN
ui/img/icons/icons8-eliminar-16.png


BIN
ui/img/icons/icons8-información-16.png


BIN
ui/img/icons/icons8-play-16.png


BIN
ui/img/icons/icons8-prismáticos-16.png


BIN
ui/img/icons/icons8-servicios-16.png


BIN
ui/img/splash.png


+ 0 - 0
validacion/__init__.py


+ 169 - 0
validacion/validacion.py

@@ -0,0 +1,169 @@
+import logging
+
+import pandas as pd
+from common.data import APPDIRS
+
+logger = logging.getLogger('simsdt.validacion')
+
+
+def load_results(filename):
+    flujos_mct = pd.read_pickle(
+        f'{APPDIRS["DATA"]}/flujos_inter_{filename}.dat')
+
+    flujos_paises = pd.read_pickle(
+        f'{APPDIRS["DATA"]}/flujos_paises_{filename}.dat')
+
+    return flujos_mct[1:2], flujos_paises[1:2]
+
+
+def validar_flujos(filename, mctp, mes):
+    finter, fnetos = load_results(filename)
+
+    # Para Guatemala
+    GU = {'FLUJOS':
+          {'EXP NS': 0,
+           'IMP NS': 0,
+           'EXP SN': 0,
+           'IMP SN': 0,
+           'POR NS': 0,
+           'POR SN': 0},
+          'CASO': 0}
+    if fnetos['GUA'][1] >= 0:
+        GU['FLUJOS']['EXP SN'] = finter['GUAELS'][1] + finter['GUAHON'][1]
+        GU['FLUJOS']['IMP SN'] = 0
+    else:
+        GU['FLUJOS']['EXP SN'] = 0
+        GU['FLUJOS']['IMP SN'] = finter['GUAELS'][1] + finter['GUAHON'][1]
+
+    # Para El Salvador
+    ES = {'FLUJOS':
+          {'EXP NS': 0,
+           'IMP NS': 0,
+           'EXP SN': 0,
+           'IMP SN': 0,
+           'POR NS': 0,
+           'POR SN': 0},
+          'CASO': 0}
+    if finter['GUAELS'][1] >= 0 and finter['ELSHON'][1] >= 0:
+        ES['FLUJOS']['IMP NS'] = fnetos['ES'][1]
+        ES['FLUJOS']['POR NS'] = finter['ELSHON'][1]
+        ES['CASO'] = 1
+    elif finter['GUAELS'][1] >= 0 and finter['ELSHON'][1] < 0:
+        ES['FLUJOS']['IMP NS'] = -1*finter['GUAELS'][1]
+        ES['FLUJOS']['IMP SN'] = finter['ELSHON'][1]
+        ES['CASO'] = 2
+    elif finter['GUAELS'][1] < 0 and finter['ELSHON'][1] < 0:
+        ES['FLUJOS']['EXP SN'] = fnetos['ES'][1]
+        ES['FLUJOS']['POR SN'] = -1*finter['ELSHON'][1]
+        ES['CASO'] = 3
+
+    # Para Honduras
+    HO = {'FLUJOS':
+          {'EXP NS': 0,
+           'IMP NS': 0,
+           'EXP SN': 0,
+           'IMP SN': 0,
+           'POR NS': 0,
+           'POR SN': 0},
+          'CASO': 0}
+
+    if finter['GUAHON'][1] >= 0 and finter['ELSHON'][1] >= 0 and finter['HONNIC'][1] >= 0:
+        HO['FLUJOS']['IMP NS'] = fnetos['HON'][1]
+        HO['FLUJOS']['POR NS'] = finter['HONNIC'][1]
+        HO['CASO'] = 1
+    elif finter['GUAHON'][1] >= 0 and finter['ELSHON'][1] >= 0 and finter['HONNIC'][1] < 0:
+        HO['FLUJOS']['IMP NS'] = -1*(finter['GUAHON'][1]+finter['ELSHON'])
+        HO['FLUJOS']['IMP SN'] = finter['HONNIC'][1]
+        HO['CASO'] = 2
+    elif finter['GUAHON'][1] < 0 and finter['ELSHON'][1] < 0 and finter['HONNIC'][1] < 0:
+        HO['FLUJOS']['EXP SN'] = fnetos['HON'][1]
+        HO['FLUJOS']['POR SN'] = -1*finter['HONNIC'][1]
+        HO['CASO'] = 3
+
+    # Para NICARAGUA
+    NI = {'FLUJOS':
+          {'EXP NS': 0,
+           'IMP NS': 0,
+           'EXP SN': 0,
+           'IMP SN': 0,
+           'POR NS': 0,
+           'POR SN': 0},
+          'CASO': 0}
+    if finter['HONNIC'][1] >= 0 and finter['NICCRI'][1] >= 0:
+        NI['FLUJOS']['IMP NS'] = fnetos['NIC'][1]
+        NI['FLUJOS']['POR NS'] = finter['NICRI'][1]
+        NI['CASO'] = 1
+    elif finter['HONNIC'][1] >= 0 and finter['NICCRI'][1] < 0:
+        NI['FLUJOS']['IMP NS'] = -1*finter['HONNIC'][1]
+        NI['FLUJOS']['IMP SN'] = finter['NICCRI'][1]
+        NI['CASO'] = 2
+    elif finter['HONNIC'][1] < 0 and finter['NICCRI'][1] < 0:
+        NI['FLUJOS']['EXP SN'] = fnetos['NIC'][1]
+        NI['FLUJOS']['POR SN'] = -1*finter['NICCRI'][1]
+        NI['CASO'] = 3
+
+    # Para COSTA RICA
+    CR = {'FLUJOS':
+          {'EXP NS': 0,
+           'IMP NS': 0,
+           'EXP SN': 0,
+           'IMP SN': 0,
+           'POR NS': 0,
+           'POR SN': 0},
+          'CASO': 0}
+    if finter['NICCRI'][1] >= 0 and finter['CRIPAN'][1] >= 0:
+        CR['FLUJOS']['IMP NS'] = fnetos['CR'][1]
+        CR['FLUJOS']['POR NS'] = finter['CRIPAN'][1]
+        CR['CASO'] = 1
+    elif finter['NICCRI'][1] >= 0 and finter['CRIPAN'][1] < 0:
+        CR['FLUJOS']['IMP NS'] = -1*finter['NICCRI'][1]
+        CR['FLUJOS']['IMP SN'] = finter['CRIPAN'][1]
+        CR['CASO'] = 2
+    elif finter['NICCRI'][1] < 0 and finter['CRIPAN'][1] < 0:
+        CR['FLUJOS']['EXP SN'] = fnetos['CR'][1]
+        CR['FLUJOS']['POR SN'] = -1*finter['CRIPAN'][1]
+        CR['CASO'] = 3
+
+    # Para Panama
+    PA = {'FLUJOS':
+          {'EXP NS': 0,
+           'IMP NS': 0,
+           'EXP SN': 0,
+           'IMP SN': 0,
+           'POR NS': 0,
+           'POR SN': 0},
+          'CASO': 0}
+    if fnetos['PAN'][1] >= 0:
+        PA['FLUJOS']['EXP SN'] = -1*finter['CRIPAN'][1]
+        PA['FLUJOS']['IMP SN'] = 0
+    else:
+        PA['FLUJOS']['EXP SN'] = 0
+        PA['FLUJOS']['IMP SN'] = -1*finter['CRIPAN'][1]
+
+    res = {
+        'GU': GU,
+        'ES': ES,
+        'HO': HO,
+        'NI': NI,
+        'CR': CR,
+        'PA': PA
+    }
+
+    for (k, v) in res.items():
+        for (kf, w) in v.items():
+            if kf == 'FLUJOS':
+                for (f, mw) in w.items():
+                    if round(abs(mw), 2) > mctp.loc[(1, k)][f]:
+                        if v['CASO'] == 1:
+                            logger.error(
+                                f"La restriccion de importacion total {k} {f} debe cambiar a {mctp.loc[mes, k][f]}")
+                        elif v['CASO'] == 2:
+                            logger.error(
+                                f"La restriccion de mct ns {k} {f} debe cambiar a {mctp.loc[mes, k][f]}")
+                        if v['CASO'] == 3:
+                            logger.error(
+                                f"La restriccion de exportacion total {k} {f} debe cambiar a {mctp.loc[mes, k][f]}")
+                        else:
+                            pass
+
+# mctp = pd.read_excel('subasta_A2101_enero.xlsx', 'mctp', index_col=[0, 1])