# --------------------------------------------------------
#   MODELO MODELO DE ASIGNACION DE CAPACIDAD DE CONEXIoN EN PHYTON-PYOMO
#   DESARROLLADO POR RIGHTSIDE S.A.S PARA LA UPME
#   junio de 2022 *** ####
# --------------------------------------------------------
#   Fila 0: Proyectos con licencia ambiental aprobada
#   Fila 1: Proyectos que requieren obras de expansión
#   Fila 2: Proyectos que NO requieren obras de expansión
# --------------------------------------------------------
# --------------------------------------------------------
#   EL MODELO SE EJECUTA EN EL ORDEN ESTABLECIDO EN EL SET FILA DEFINIDO EN datosentrada.py
#   LA FORMA CORRECTA DE EJECUTAR EL MODELO ES LA SIGUIENTE:
#   1. Ejecutar el MACC solo con los proyectos de la fila 0.
#   2. Ejecutar el MACC con los proyectos de la fila 0 asignados en el paso anterior
#       e incluir los demás proyectos de la fila 1 y fila 2. Tambien se pueden incluir
#       los proyectos de la fila 0 que no fueron asignados pero marcados como fila 1 o 2.
#   NOTA:
#       * Cuando existen proyectos de fila 0 y fila 1 o 2, el modelo asigna los proyectos de
#         la fila 0 como obligatorios. Cuando solo hay proyectos de fila 0 no son obligatorios.
#       **Los proyectos de la fila 1 deben tener una obra relacionada. Si el usuario desea
#         puede incluir una obra de costo cero y asociarla a los proyectos de fila 1 que
#         no tienen una obra especial relacionada o que no se quiera modelar la obra.
# --------------------------------------------------------

from pyomo.environ import *
from macc_entradas import *
from macc_salidas import *
import xlwings as xw
import warnings
import pandas as pd
import numpy as np 

warnings.filterwarnings("ignore")

print()
print( " EJECUTANDO MODELO MACC 3.0 ")
print()

#Rango de periodos
iiPERIODOS = set(list(range(PI,PF+1)))   
iiANOS = set()
iiProyectosF0 = set(iProyectosF0.nombre)
iiProyectosF1 = set(iProyectosF1.nombre)
iiProyectosF2 = set(iProyectosF2.nombre)
iiBarras = set(iBarras.nombre)
iiCriterios = set(iCriterios.nombre)
iiZonas = set(iZonas.nombre)

zonaBarra_rel = set()
iiProyectos =  set(iProyectos.nombre)
iiObras =  set()
iiObras = set(iObras.nombre)
iiAreas =  set()
iiAreas = set(iAreas.nombre)
iiBarrasCorto = set(iBarrasCorto.barra)

ESTADO_INICIAL = {}
ESTADO_INICIAL_OBRA = {}
ACTIVO = {}
CALIFICACION_TOTAL = {}
CALIFICACION = {}
MAXCALIFICACION = {}
FPO_SOLICITADA = {}
FECHA_OBRA = {}
FPO_MAX = {}
BINARIOAS_O = pd.DataFrame()
INTERCAMBIO_A = pd.DataFrame()
BENEFICIO_M = pd.DataFrame()
CAPACIDADBARRAS = {}
MWBARRAS = {}
PORCENTAJEBARRAS = {}
MWBZONAS= {}
CAPACIDADZONAS= {}
PORCENTAJEZONAS= {}

CAPACIDADAREA = {}
PORCENTAJEAREAS= {}

for p in iiProyectos:
    for c in iiCriterios:
        CALIFICACION[p,c] = 0
        MAXCALIFICACION[c] = 0

if ESCALAR == 1:
    # Encontrar la maxima calificacion
    MAXCALIFICACION["B_Ambiental"] = 0
    MAXCALIFICACION["BT_Confi"] = 0
    MAXCALIFICACION["BT_Flex"] = 0
    MAXCALIFICACION["EC_RE"] = 0
    MAXCALIFICACION["EC_RP"] = 0
    MAXCALIFICACION["EC_Per"] = 0
    MAXCALIFICACION["EC_Mar"] = 0

    for p in iiProyectos:
        if calificacionProyectos.B_Ambiental[p] > MAXCALIFICACION["B_Ambiental"]:
            MAXCALIFICACION["B_Ambiental"] = calificacionProyectos.B_Ambiental[p]
        if calificacionProyectos.BT_Confi[p] > MAXCALIFICACION["BT_Confi"]:
            MAXCALIFICACION["BT_Confi"] = calificacionProyectos.BT_Confi[p]
        if calificacionProyectos.BT_Flex[p] > MAXCALIFICACION["BT_Flex"]:
            MAXCALIFICACION["BT_Flex"] = calificacionProyectos.BT_Flex[p]
        if calificacionProyectos.EC_RE[p] > MAXCALIFICACION["EC_RE"]:
            MAXCALIFICACION["EC_RE"] = calificacionProyectos.EC_RE[p]
        if calificacionProyectos.EC_RP[p] > MAXCALIFICACION["EC_RP"]:
            MAXCALIFICACION["EC_RP"] = calificacionProyectos.EC_RP[p]
        if calificacionProyectos.EC_Per[p] > MAXCALIFICACION["EC_Per"]:
            MAXCALIFICACION["EC_Per"] = calificacionProyectos.EC_Per[p]
        if calificacionProyectos.EC_Mar[p] > MAXCALIFICACION["EC_Mar"]:
            MAXCALIFICACION["EC_Mar"] = calificacionProyectos.EC_Mar[p]

    for p in iiProyectos:
        if MAXCALIFICACION["B_Ambiental"] > 0:
            CALIFICACION[p,"B_Ambiental"] = calificacionProyectos.B_Ambiental[p]/MAXCALIFICACION["B_Ambiental"]
        else:
            CALIFICACION[p,"B_Ambiental"] = 0
        if MAXCALIFICACION["BT_Confi"] > 0:
            CALIFICACION[p,"BT_Confi"] = calificacionProyectos.BT_Confi[p]/MAXCALIFICACION["BT_Confi"]
        else:
            CALIFICACION[p,"BT_Confi"] = 0
        if MAXCALIFICACION["BT_Flex"] > 0:
            CALIFICACION[p,"BT_Flex"] = calificacionProyectos.BT_Flex[p]/MAXCALIFICACION["BT_Flex"]
        else:
            CALIFICACION[p,"BT_Flex"] = 0
        if MAXCALIFICACION["EC_RE"] > 0:
            CALIFICACION[p,"EC_RE"] = calificacionProyectos.EC_RE[p]/MAXCALIFICACION["EC_RE"]
        else:
            CALIFICACION[p,"EC_RE"] = 0
        if MAXCALIFICACION["EC_RP"] > 0:
            CALIFICACION[p,"EC_RP"] = calificacionProyectos.EC_RP[p]/MAXCALIFICACION["EC_RP"]
        else:
            CALIFICACION[p,"EC_RP"] = 0
        if MAXCALIFICACION["EC_Per"] > 0:
            CALIFICACION[p,"EC_Per"] = calificacionProyectos.EC_Per[p]/MAXCALIFICACION["EC_Per"]
        else:
            CALIFICACION[p,"EC_Per"] = 0
        if MAXCALIFICACION["EC_Mar"] > 0:
            CALIFICACION[p,"EC_Mar"] = calificacionProyectos.EC_Mar[p]/MAXCALIFICACION["EC_Mar"]
        else:
            CALIFICACION[p,"EC_Mar"] = 0
else:
    for p in iiProyectos:
        CALIFICACION[p,"B_Ambiental"] = calificacionProyectos.B_Ambiental[p]
        CALIFICACION[p,"BT_Confi"] = calificacionProyectos.BT_Confi[p]
        CALIFICACION[p,"BT_Flex"] = calificacionProyectos.BT_Flex[p] 
        CALIFICACION[p,"EC_RE"] = calificacionProyectos.EC_RE[p]
        CALIFICACION[p,"EC_RP"] = calificacionProyectos.EC_RP[p]
        CALIFICACION[p,"EC_Per"] = calificacionProyectos.EC_Per[p]
        CALIFICACION[p,"EC_Mar"] = calificacionProyectos.EC_Mar[p]

for p in iiProyectos:
    CALIFICACION_TOTAL[p] = sum (criterios.ponderacion[c]*CALIFICACION[p,c] for c in iiCriterios) 

for p in proyectos.index:
    FPO_SOLICITADA[p] = proyectos.periodoIni[p]
    FPO_MAX[p] = proyectos.fpomax[p]
    ACTIVO[p] = proyectos.activo[p]
    ESTADO_INICIAL[p] = min(proyectos.obligatorio[p],ACTIVO[p])
    if proyectos.fila[p] == 0 and len(iProyectosF1) > 0  and len(iProyectosF2) > 0:
        ESTADO_INICIAL[p] = 1 

for o in obras.index:
    ESTADO_INICIAL_OBRA[o] = min(obras.obligatorio[o],OBRASENFILA2)
    FECHA_OBRA[o] = obras.periodoini[o]
        
#iizonaBarra = zonaBarra.groupby(["nombre", "periodo"])["barra"].apply(lambda x: x.tolist() ).to_dict()
iizonaBarra = zonaBarra.groupby(["nombre"])["barra"].apply(lambda x: x.tolist() ).to_dict()
Diccionario_Datos = {}

salir = 0
for fila in FILAS:
    if fila == 0: fila_print = 0
    if fila == 1: fila_print = 1
    if fila == 2: fila_print = 2
    print()
    print(" Asignando Fila ", fila_print)
    print()

    if fila == 0:
        iiProyectos = iiProyectosF0
    if fila == 1:
        iiProyectos = iiProyectosF1.union(iiProyectosF0)
        iiProyectos = iiProyectos.union(iiProyectosF2)
    if fila == 2:
        iiProyectos = iiProyectosF2.union(iiProyectosF0)
        
    if len(iiProyectos) == 0:
        print()
        print(" NO HAY PROYECTOS PARA ASIGNAR EN LA FILA ",fila)
        salir = 1
    activos = sum(proyectos.activo[p] for p in iiProyectos)
    if activos == 0:
        print()
        print(" NO HAY PROYECTOS PARA ASIGNAR ")
        sys.exit()

    if salir == 0:
        # MODELO--->
        macc = ConcreteModel()
        macc.dual = Suffix(direction=Suffix.IMPORT)

        # --------------------------------------------------------
        #   DEFINICIoN DE VARIABLES
        # --------------------------------------------------------
        # Variables Binarias
        macc.binariaP = Var(iiProyectos,iiPERIODOS, domain=Boolean, initialize=1)
        macc.binariaO = Var(iiObras,iiPERIODOS, domain=Boolean, initialize=1)
        macc.IntercambioA = Var(iiAreas,iiPERIODOS, domain=Reals, initialize=1)

        #------------------------------
        #   FUNCION OBJETIVO
        #------------------------------
        def Beneficio_rule(macc):
            expr  = sum (criterios.ponderacion[c]*proyectos.capacidad[p]*CALIFICACION[p,c]*macc.binariaP[p,t] for p in iiProyectos for c in iiCriterios for t in iiPERIODOS) 
            expr  -= sum (obras.costo[o]*macc.binariaO[o,t] for o in obras.index for t in iiPERIODOS) 
            return expr
        macc.Beneficio = Objective(rule=Beneficio_rule, sense=maximize)

        #------------------------------
        #   CONTROL DE CAPACIDAD DE CORTOCIRCUITO
        #------------------------------
        if len(iiBarrasCorto) > 0:
            def r1_rule_corto(macc,b,t):
                ecuacion1_2 = sum (macc.binariaP[c[0],t]*cortocircuito.aportecortocircuito[c] 
                                for c in cortocircuito.index
                                if c[1] == b
                                if c[0] in iiProyectos )
                if not bool(ecuacion1_2):
                    return Constraint.Skip

                return ecuacion1_2 <= barras.cortocircuito[b,t]*barras.factorcorto[b,t] + \
                                sum(obras.cortocircuito[o]*macc.binariaO[o,t]
                                    for o in obras.index
                                    if obras.barra[o] == b
                                    if not str(obras.cortocircuito[o]) == 'nan'
                                )
            macc.r1_capacidadCorto = Constraint(iiBarrasCorto,iiPERIODOS,rule=r1_rule_corto)
        #------------------------------
        #   CONTROL DE CAPACIDAD BARRA
        #------------------------------

        def r1_rule(macc,b,t):
            ecuacion1 = sum ( macc.binariaP[p,t]*proyectos.capacidad[p]  
                    for p in iiProyectos
                    if proyectos.barra[p] == b )
            if not bool(ecuacion1):
                return Constraint.Skip
            return ecuacion1 <= barras.capacidad[b,t]*barras.factorcapacidad[b,t] + \
                                sum(obras.capacidadbarra[o]*macc.binariaO[o,t]
                                    for o in obras.index
                                    if obras.barra[o] == b
                                    if not str(obras.capacidadbarra[o]) == 'nan'
                                )
        macc.r1_capacidadBarra = Constraint(iiBarras,iiPERIODOS,rule=r1_rule)
        #------------------------------
        #   CONTROL DE CAPACIDAD ZONA
        #------------------------------
        def r2_rule(macc,z,t):
            ecuacion2 = sum (macc.binariaP[p,t]*proyectos.capacidad[p]  
                        for p in iiProyectos
                        if proyectos.barra[p] in iizonaBarra[z]
                        )
            if not bool(ecuacion2):
                return Constraint.Skip
            return ecuacion2 <= zonas.capacidad[z,t]*zonas.factor[z,t] + \
                                    sum(obras.capacidadzona[o]*macc.binariaO[o,t]
                                    for o in obras.index
                                    if obras.zona[o] == z
                                    if not str(obras.capacidadzona[o]) == 'nan'
                                )

        macc.r2_capacidadZona = Constraint(iiZonas,iiPERIODOS,rule=r2_rule)

        #------------------------------
        #   CONTROL DEL ESTADO INICIAL PROYECTOS
        #------------------------------
        def r3_rule(macc,p,t):
            if FPO_SOLICITADA[p] > t:
                return Constraint.Skip
            else:
                return macc.binariaP[p,t] >= ESTADO_INICIAL[p]
        macc.r3_estadoInicial = Constraint(iiProyectos,iiPERIODOS,rule=r3_rule)

        #------------------------------
        #   CONTROL DE ESTADO ACTIVO PROYECTOS
        #------------------------------
        def r4_rule(macc,p,t):
            return macc.binariaP[p,t] <= ACTIVO[p]
        macc.r4_activo = Constraint(iiProyectos,iiPERIODOS,rule=r4_rule)

        #------------------------------
        #   CONTROL DE FPO INICIAL PROYECTOS
        #------------------------------
        
        def r5_rule(macc,p,t):
            if t == PI:
                return macc.binariaP[p,t] >= ESTADO_INICIAL[p]
            else:
                return macc.binariaP[p,t] >= macc.binariaP[p,t-1]
        macc.r5_fpoIni = Constraint(iiProyectos,iiPERIODOS,rule=r5_rule)
        
        def r5_1_rule(macc,p,t):
            if FPO_SOLICITADA[p] > t:
                return macc.binariaP[p,t] == 0
            else:
                return Constraint.Skip
        macc.r5_1_fpoIni = Constraint(iiProyectos,iiPERIODOS,rule=r5_1_rule)
        
        # def r5_2_rule(macc,p,t):
        #     if FPO_SOLICITADA[p] < t and t > PI:
        #         return macc.binariaP[p,t] == macc.binariaP[p,t-1]
        #     else:
        #         return Constraint.Skip
        # macc.r5_2_fpoIni = Constraint(iiProyectos,iiPERIODOS,rule=r5_2_rule)
            
        #------------------------------
        #   LIMITES DE AREAS
        #------------------------------
        def r8_rule(macc,a,t):
            ecuacion8 = sum ( macc.binariaP[p,t]*proyectos.capacidad[p]  
                        for p in iiProyectos
                        if proyectos.area[p] == a 
                        ) + areas.generacion[a,t] + macc.IntercambioA[a,t]
            if not bool(ecuacion8):
                return Constraint.Skip
            return ecuacion8 == areas.demanda[a,t]
        macc.r8_limiteAreas = Constraint(iiAreas,iiPERIODOS,rule=r8_rule)

        def r9_rule(macc,a,t):
            return macc.IntercambioA[a,t] <= ( areas.limiteimportacion[a,t]   \
                                        + sum (obras.capacidadarea[o]*macc.binariaO[o,t]
                                            for o in obras.index
                                            if obras.area[o] == a
                                            if not str(obras.capacidadarea[o]) == 'nan')  )*areas.factorimportacion[a,t]
        macc.r9_ImportacionAreas = Constraint(iiAreas,iiPERIODOS,rule=r9_rule)
        
        def r10_rule(macc,a,t):          
            return macc.IntercambioA[a,t] >= - ( areas.limiteexportacion[a,t]   \
                                            + sum (obras.capacidadarea[o]*macc.binariaO[o,t]
                                                for o in obras.index
                                                if obras.area[o] == a
                                                if not str(obras.capacidadarea[o]) == 'nan') )*areas.factorexportacion[a,t]
        macc.r10_ImportacionAreas = Constraint(iiAreas,iiPERIODOS,rule=r10_rule)

        if OBRASENFILA2 == 1 or fila == 1:    # Bandera para permitir obras en fila 2
            #------------------------------
            #   CONTROL DEL ESTADO INICIAL OBRAS
            #------------------------------
            def r6_rule(macc,o,t):
                if FECHA_OBRA[o] >= t:
                    return Constraint.Skip
                else:
                    return macc.binariaO[o,t] >= ESTADO_INICIAL_OBRA[o]
            macc.r6_estadoInicialObra = Constraint(iiObras,iiPERIODOS,rule=r6_rule)
            #------------------------------
            #   CONTROL DE FPO INICIAL OBRAS
            #------------------------------
            def r7_rule(macc,o,t):
                if FECHA_OBRA[o] > t:
                    return macc.binariaO[o,t] == 0
                else:
                    return Constraint.Skip
            macc.r7_fechaIniObra = Constraint(iiObras,iiPERIODOS,rule=r7_rule)
            #------------------------------
            #   OBRAS DEPENDIENTES
            #------------------------------
            macc.r11_bindependiente = ConstraintList()
            for o in obras.index:
                for t in iiPERIODOS:
                    if not str(obras.dependiente[o]) == 'nan':
                        macc.r11_bindependiente.add ( 
                            macc.binariaO[o,t] <= macc.binariaO[obras.dependiente[o],t]
                                )

            #------------------------------
            #   OBRAS EXCLUYENTES
            #------------------------------
            macc.r12_binexcluyente = ConstraintList()
            for o in obras.index:
                for t in iiPERIODOS:
                    if not str(obras.excluyente[o]) == 'nan':
                        macc.r12_binexcluyente.add ( 
                            macc.binariaO[o,t] <= 1 - macc.binariaO[obras.excluyente[o],t]
                        )
            #------------------------------
            #   RELACION ENTRE OBRAS Y PROYECTOS DEPENDIENTES
            #------------------------------
            macc.r15_ObrasProyectos = ConstraintList()
            for p in iiProyectos:
                for t in iiPERIODOS:
                    if not str(proyectos.obra[p]) == 'nan':
                        macc.r15_ObrasProyectos.add ( 
                            macc.binariaP[p,t] <= macc.binariaO[proyectos.obra[p],t]
                                )

        elif fila == 2 and OBRASENFILA2 == 0: #Si no se permiten obras en fila 2
            def r7_rule_aux(macc,o,t):
                return macc.binariaO[o,t] == 0
            macc.r7_controlObras = Constraint(iiObras,iiPERIODOS,rule=r7_rule_aux)

        #------------------------------
        #   PROYECTOS EXCLUYENTES
        #------------------------------
        macc.r13_proyexcluyente = ConstraintList()
        for p in iiProyectos:
            for t in iiPERIODOS:
                if not str(proyectos.excluyente[p]) == 'nan':
                    macc.r13_proyexcluyente.add ( 
                        macc.binariaP[p,t] <= 1 - macc.binariaP[proyectos.excluyente[p],t]
                    )
# --------------------------------------------------------
# FIN DEL MODELO MATEMATICO
# --------------------------------------------------------

        # --------------------------------------------------------
        #   SOLUCIONAR EL PROBLEMA
        # --------------------------------------------------------

        opt = SolverFactory(OPTIMIZADOR) 

        if OPTIMIZADOR == 'cbc':
            opt.options['ratioGap'] = 0
            opt.options['allowableGap'] = TOLERANCIA
            opt.options['sec'] = TIEMPOLIMITE
            
        if OPTIMIZADOR == 'cplex':
            opt.options['mipgap'] = 0
            opt.options['mip_tolerances_absmipgap'] = TOLERANCIA
            opt.options['timelimit'] = TIEMPOLIMITE

        macc.write("macc"+str(fila)+"_"+str(t)+".lp",io_options={"symbolic_solver_labels":True})

        print ()
        print("Optimizador: " , opt.name) 
        print ()

        # Ejecutar modelo binario
        results = opt.solve(macc,tee=1,logfile ='macc.log', keepfiles= 0,symbolic_solver_labels=True) # solves and updates instance

        if (results.solver.status == SolverStatus.ok) and (results.solver.termination_condition == TerminationCondition.optimal):

            print ("Se encontro solucion optima: ")
            print ()
            print ("Funcion Objetivo PROBLEMA : ", value(macc.Beneficio))

        elif (results.solver.termination_condition == TerminationCondition.infeasible):
            print("EL PROBLEMA ES INFACTIBLE") 
            sys.exit()   
        else:
            print ("Solver Status: ",  results.solver.status)
            print ()
            sys.exit()
        
        for t in iiPERIODOS:
            
            PROYECTOS_APROBADOS = {}
            OBRAS_APROBADAS = {}

            for p in iiProyectos:
                PROYECTOS_APROBADOS[p,t] = macc.binariaP[p,t].value
                ESTADO_INICIAL[p] = macc.binariaP[p,t].value
                
            for o in iiObras:
                ESTADO_INICIAL_OBRA[o] = macc.binariaO[o,t].value
                OBRAS_APROBADAS[o,t] = macc.binariaO[o,t].value

            SalidasMACC = inserInto (  iiPERIODOS, iiProyectos, PROYECTOS_APROBADOS, CALIFICACION_TOTAL, FPO_SOLICITADA,
                                        iiObras, OBRAS_APROBADAS)

            Diccionario_Datos[str(t)] = SalidasMACC['salidas_macc']

            # SALIDAS
            myDataFrame = pd.DataFrame()
    
            for df in Diccionario_Datos.keys():
                myDataFrame = myDataFrame.append(Diccionario_Datos[df])
    
            # VALORES DE TABLAS RESUMEN Y RESUMEN %
            valores_capacidad = proyectos["capacidad"].copy()
            dic_capacidad = valores_capacidad.to_dict()
    
            valores_tipo = proyectos["tipo"].copy()
            dic_tipo = valores_tipo.to_dict()
    
            salida_capacidad = myDataFrame.copy()
    
            salida_capacidad['capacidad'] = salida_capacidad['nombre'].map(dic_capacidad)
            salida_capacidad['tipo'] = salida_capacidad['nombre'].map(dic_tipo)
    
            salida_capacidad['capacidad aprobada'] = salida_capacidad['capacidad']*salida_capacidad['aprobado']
    
            salida_capacidad.drop(["calificacion","aprobado", "capacidad", "nombre"], axis=1, inplace = True)
    
            df_salida = salida_capacidad.groupby(["periodo", "tipo"]).sum()
            df_salida.reset_index(inplace = True)
            resumen = df_salida.pivot( index = "tipo",columns="periodo")  
    
            # RESUMEN %
            data_salida = resumen.copy()
            data_salida.columns = data_salida.columns.droplevel()
    
            salida_porcentual = data_salida.div(data_salida.sum(axis=0), axis=1)
    
    
    
            # SALIDA DE VALORES FILA 0, 1 Y FILA 2
            dfnuevo = myDataFrame.pivot( index = "nombre",columns="periodo")
            dfnuevo.reset_index(inplace = True)
            
            dfnuevo['capacidad',''] = dfnuevo.loc[:,('nombre','')]
            dfnuevo['tipo',''] = dfnuevo.loc[:,('nombre','')]
            dfnuevo['barra',''] = dfnuevo.loc[:,('nombre','')]
            dfnuevo['periodoIni',''] = dfnuevo.loc[:,('nombre','')]
    
            diccionario_proyectos = proyectos[["capacidad", "tipo","barra",'periodoIni']].copy().to_dict() 
            
            listaProyectos = list(diccionario_proyectos.keys())
            for llaves in listaProyectos:
                diccionario_proyectos[(llaves, "")] = diccionario_proyectos.pop(llaves)
    
    
            dfnuevo.replace(diccionario_proyectos, inplace = True)
    
            dfnuevo.set_index([('nombre',''),('barra',''),('tipo',''),('capacidad',''),('periodoIni','')],inplace = True)
    
            dfnuevo.index.names = ['nombre','barra','tipo','capacidad',"periodoIni"]
    
            dfnuevo = dfnuevo.sort_values([('calificacion', PI)], ascending=False).copy()
    
    
            # SALIDA DE VALORES RELACIONADOS CON BINARIAO Expansión
            E_grid_data = {(exp, an): valor.value for (exp, an), valor in macc.binariaO.items()}
            df = pd.DataFrame.from_dict(E_grid_data, orient="index", columns=["Valor"])
            df["id año"] = t 
            df["id fila"] = fila
            BINARIOAS_O = BINARIOAS_O.append(df)        
    
            # SALIDA DE VALORES RELACIONADOS CON INTERCAMBIO AREA    
            E_grid_data = {(exp, an): valor.value for (exp, an), valor in macc.IntercambioA.items()}
            df = pd.DataFrame.from_dict(E_grid_data, orient="index", columns=["Valor"])
            df["id año"] = t 
            df["id fila"] = fila
            INTERCAMBIO_A = INTERCAMBIO_A.append(df) 
    
    
            # SALIDA DE VALORES RELACIONADOS CON BENEFICIO        
            E_grid_data = {("beneficio"): value(macc.Beneficio)/1000000}
            df = pd.DataFrame.from_dict(E_grid_data, orient="index", columns=["Valor"])
            df["id año"] = t 
            df["fila"] = fila
            BENEFICIO_M = BENEFICIO_M.append(df) 
    
    
            # PORCENTAJE POR BARRAS
            for b in iiBarras:
                    
                MWBARRAS[b,t,fila] = sum ( macc.binariaP[p,t].value*proyectos.capacidad[p]  
                        for p in iiProyectos
                        if proyectos.barra[p] == b )
    
                CAPACIDADBARRAS[b,t,fila] = barras.capacidad[b,t]*barras.factorcapacidad[b,t] + \
                                sum(obras.capacidadbarra[o]*macc.binariaO[o,t].value
                                    for o in obras.index
                                    if obras.barra[o] == b
                                    if not str(obras.capacidadbarra[o]) == 'nan'
                                )
    
                PORCENTAJEBARRAS[b,t,fila] = (MWBARRAS[b,t,fila]/CAPACIDADBARRAS[b,t,fila]) 
    
            # PORCENTAJE POR ZONAS
            for z in iiZonas:
                    
                    MWBZONAS[z,t,fila] = sum ( macc.binariaP[p,t].value*proyectos.capacidad[p]  
                            for p in iiProyectos
                            if proyectos.barra[p] in iizonaBarra[z]
                            )
    
                    CAPACIDADZONAS[z,t,fila] = zonas.capacidad[z,t]*zonas.factor[z,t] + \
                                        sum(obras.capacidadzona[o]*macc.binariaO[o,t].value
                                        for o in obras.index
                                        if obras.zona[o] == z
                                        if not str(obras.capacidadzona[o]) == 'nan'
                                    )
    
                    PORCENTAJEZONAS[z,t,fila] = (MWBZONAS[z,t,fila]/CAPACIDADZONAS[z,t,fila]) 
    
            # PORCENTAJE POR AREAS
            for a in iiAreas:
                if macc.IntercambioA[a,t].value >= 0:
    
                    CAPACIDADAREA[a,t,fila] = ( areas.limiteimportacion[a,t]   \
                                                + sum (obras.capacidadarea[o]*macc.binariaO[o,t].value
                                                    for o in obras.index
                                                    if obras.area[o] == a
                                                    if not str(obras.capacidadarea[o]) == 'nan')  )*areas.factorimportacion[a,t]
                else:
    
                    CAPACIDADAREA[a,t,fila] = ( areas.limiteexportacion[a,t]   \
                                                + sum (obras.capacidadarea[o]*macc.binariaO[o,t].value
                                                    for o in obras.index
                                                    if obras.area[o] == a
                                                    if not str(obras.capacidadarea[o]) == 'nan' ) )*areas.factorexportacion[a,t]
    
    
                PORCENTAJEAREAS[a,t,fila] =( macc.IntercambioA[a,t].value/CAPACIDADAREA[a,t,fila])
            # escritura de archivos a excel DHOG
            
    
            if fila_print == 0:
    
                fila0_valores = dfnuevo
                resumen0_valores = resumen
                resumen0_porcen_valores =  salida_porcentual
    
            
            if fila_print == 1:
    
                fila1_valores = dfnuevo
                resumen1_valores = resumen
                resumen1_porcen_valores =  salida_porcentual
    
            if fila_print == 2:
                
                fila2_valores = dfnuevo
                resumen2_valores = resumen
                resumen2_porcen_valores =  salida_porcentual


if salir == 0:
    # # CONVERSIÓN DE TABLAS FINALES EXPANSIÓN
    # BINARIOAS_O.reset_index(inplace = True)
    # BINARIOAS_O[['expansion', 'periodo']] = pd.DataFrame(BINARIOAS_O['index'].tolist(), index=BINARIOAS_O.index)
    # BINARIOAS_O.drop(["index"], axis = 1, inplace = True)

    # BINARIOAS_O["filtro"] = np.where(BINARIOAS_O["periodo"] == BINARIOAS_O["id año"], True, False)
    # BINARIOAS_O = BINARIOAS_O[BINARIOAS_O.filtro]
    # BINARIOAS_O.drop(["periodo", "filtro"], axis = 1, inplace = True)

    # BINARIOAS_O_FINAL = BINARIOAS_O.copy()
    # BINARIOAS_O_FINAL.rename(columns={"id fila": "fila"}, inplace = True)


    # if not BINARIOAS_O_FINAL.empty:
    #     DF_BINARIOS_SALIDA = BINARIOAS_O_FINAL.pivot_table(index = ["expansion", "fila"], columns="id año")
    #     DF_BINARIOS_SALIDA.columns = DF_BINARIOS_SALIDA.columns.droplevel()

    # else:
    #     DF_BINARIOS_SALIDA = pd.DataFrame()



    # CONVERSIÓN DE TABLA DE INTERCAMBIO A 
    if not INTERCAMBIO_A.empty:
        INTERCAMBIO_A.reset_index(inplace = True)
        INTERCAMBIO_A[['area', 'periodo']] = pd.DataFrame(INTERCAMBIO_A['index'].tolist(), index=INTERCAMBIO_A.index)
        INTERCAMBIO_A.drop(["index"], axis = 1, inplace = True)
        INTERCAMBIO_A["filtro"] = np.where(INTERCAMBIO_A["periodo"] == INTERCAMBIO_A["id año"], True, False)
        INTERCAMBIO_A = INTERCAMBIO_A[INTERCAMBIO_A.filtro]
        INTERCAMBIO_A.drop(["periodo", "filtro"], axis = 1, inplace = True)
        INTERCAMBIO_A_FINAL = INTERCAMBIO_A.copy() 
        INTERCAMBIO_A_FINAL.rename(columns={"id fila": "fila"}, inplace = True)

        DF_INTERCAMBIO = INTERCAMBIO_A_FINAL.pivot_table(index = ["area", "fila"], columns="id año")
        DF_INTERCAMBIO.columns = DF_INTERCAMBIO.columns.droplevel()

    else:
        DF_INTERCAMBIO = pd.DataFrame()



    # CONVERSION DE VALORES DE BENEFICIO 
    if not BENEFICIO_M.empty:
        BENEFICIO_M_FINAL = BENEFICIO_M.pivot(columns="id año", index = "fila") 
        BENEFICIO_M_FINAL.columns = BENEFICIO_M_FINAL.columns.droplevel()
    else:
        BENEFICIO_M_FINAL = pd.DataFrame()


    # CONVERSION DE VALORES DE PORCENTAJE BARRA
    df = pd.DataFrame.from_dict(PORCENTAJEBARRAS, orient="index", columns=["PORCENTAJE"])
    #pd.set_option('display.max_rows', None)
    #print(df)
    df.reset_index(inplace = True)
    df[['barra', 'periodo',"fila"]] = pd.DataFrame(df['index'].tolist(), index=df.index)
    df.drop("index", axis = 1, inplace = True)
    df_sa = df.pivot_table(index = ["barra", "fila"], columns="periodo")
    df_sa.columns = df_sa.columns.droplevel()
    PORCENTAJEBARRAS_FINAL = df_sa.copy()


    # CONVERSION DE VALORES DE PORCENTAJE ZONAS
    df = pd.DataFrame.from_dict(PORCENTAJEZONAS, orient="index", columns=["PORCENTAJE"])
    df.reset_index(inplace = True)
    if not df.empty:
        df[['zona', 'periodo', "fila"]] = pd.DataFrame(df['index'].tolist(), index=df.index)
        df.drop("index", axis = 1, inplace = True)
        df_sa = df.pivot_table(index = ["zona", "fila"], columns="periodo")
        df_sa.columns = df_sa.columns.droplevel()
    else:
        df_sa = pd.DataFrame()
    PORCENTAJEZONAS_FINAL = df_sa.copy()



    # CONVERSION DE VALORES DE PORCENTAJE AREAS
    df = pd.DataFrame.from_dict(PORCENTAJEAREAS, orient="index", columns=["PORCENTAJE"])
    df.reset_index(inplace = True)
    if not df.empty:
        df[['area', 'periodo', "fila"]] = pd.DataFrame(df['index'].tolist(), index=df.index)
        df.drop("index", axis = 1, inplace = True)
        df_sa = df.pivot_table(index = ["area","fila"], columns="periodo")
        df_sa.columns = df_sa.columns.droplevel()
    else:
        df_sa = pd.DataFrame()

    PORCENTAJEAREAS_FINAL = df_sa.copy()


    # ORGANIZAR DATAFRAMES EN UNO SOLO

    # FILA 0, 1 Y 2
    if len(iProyectosF0) > 0:
        fila0_valores.reset_index(inplace = True)
        fila0_valores['Fila',''] = 0
        fila0_valores.set_index([('nombre',''),('barra',''),('tipo',''),('capacidad',''),('periodoIni',''), ("Fila","")],inplace = True)        
        fila0_valores.index.names = ['nombre','barra','tipo','capacidad',"periodoIni", "Fila"]


    if len(iProyectosF1) > 0:
        fila1_valores.reset_index(inplace = True)
        fila1_valores['Fila',''] = 1
        fila1_valores.set_index([('nombre',''),('barra',''),('tipo',''),('capacidad',''),('periodoIni',''), ("Fila","")],inplace = True)        
        fila1_valores.index.names = ['nombre','barra','tipo','capacidad',"periodoIni", "Fila"]


    if len(iProyectosF2) > 0:
        fila2_valores.reset_index(inplace = True)
        fila2_valores['Fila',''] = 2
        fila2_valores.set_index([('nombre',''),('barra',''),('tipo',''),('capacidad',''),('periodoIni',''), ("Fila","")],inplace = True)        
        fila2_valores.index.names = ['nombre','barra','tipo','capacidad',"periodoIni", "Fila"]

    if len(iProyectosF0) > 0:
        salida_filas = fila0_valores
        if len(iProyectosF1) > 0:
            salida_filas = salida_filas.append(fila1_valores)
            if len(iProyectosF2) > 0:
                salida_filas = salida_filas.append(fila2_valores)
        else:
            if len(iProyectosF2) > 0:
                salida_filas = salida_filas.append(fila2_valores)
    else:
        if len(iProyectosF1) > 0:
            salida_filas = fila1_valores
            if len(iProyectosF2) > 0:
                salida_filas = salida_filas.append(fila2_valores)
        else:
            salida_filas = fila2_valores
            
    # RESUMEN 1 Y 2
    if len(iProyectosF0)  > 0:
        resumen0_valores.reset_index(inplace = True)
        resumen0_valores['Fila',''] = 0
        resumen0_valores.set_index([('tipo',''), ("Fila","")],inplace = True)        
        resumen0_valores.index.names = ['tipo', "Fila"]


    if len(iProyectosF1)  > 0:
        resumen1_valores.reset_index(inplace = True)
        resumen1_valores['Fila',''] = 1
        resumen1_valores.set_index([('tipo',''), ("Fila","")],inplace = True)        
        resumen1_valores.index.names = ['tipo', "Fila"]

    if len(iProyectosF2)  > 0:
        resumen2_valores.reset_index(inplace = True)
        resumen2_valores['Fila',''] = 2
        resumen2_valores.set_index([('tipo',''), ("Fila","")],inplace = True)        
        resumen2_valores.index.names = ['tipo', "Fila"]

    if len(iProyectosF0) > 0:
        salida_resumen = resumen0_valores
        if len(iProyectosF1) > 0:
            salida_resumen = salida_resumen.append(resumen1_valores)
            if len(iProyectosF2) > 0:
                salida_resumen = salida_resumen.append(resumen2_valores)
        else:
            if len(iProyectosF2) > 0:
                salida_resumen = salida_resumen.append(resumen2_valores)
    else:
        if len(iProyectosF1) > 0:
            salida_resumen = resumen1_valores
            if len(iProyectosF2) > 0:
                salida_resumen = salida_resumen.append(resumen2_valores)
        else:
            salida_resumen = resumen2_valores
    
    # RESUMEN PORCENTUAL 1 Y 2

    if len(iProyectosF0)  > 0:
        resumen0_porcen_valores.reset_index(inplace = True)
        resumen0_porcen_valores['Fila'] = 0
        resumen0_porcen_valores.set_index(['tipo', "Fila"],inplace = True) 

    if len(iProyectosF1)  > 0:
        resumen1_porcen_valores.reset_index(inplace = True)
        resumen1_porcen_valores['Fila'] = 1
        resumen1_porcen_valores.set_index(['tipo', "Fila"],inplace = True)        


    if len(iProyectosF2)  > 0:
        resumen2_porcen_valores.reset_index(inplace = True)
        resumen2_porcen_valores['Fila'] = 2
        resumen2_porcen_valores.set_index(['tipo', "Fila"],inplace = True)        

    if len(iProyectosF0) > 0:
        salida_resumen_porcen = resumen0_porcen_valores
        if len(iProyectosF1) > 0:
            salida_resumen_porcen = salida_resumen_porcen.append(resumen1_porcen_valores)
            if len(iProyectosF2) > 0:
                salida_resumen_porcen = salida_resumen_porcen.append(resumen2_porcen_valores)
        else:
            if len(iProyectosF2) > 0:
                salida_resumen_porcen = salida_resumen_porcen.append(resumen2_porcen_valores)
    else:
        if len(iProyectosF1) > 0:
            salida_resumen_porcen = resumen1_porcen_valores
            if len(iProyectosF2) > 0:
                salida_resumen_porcen = salida_resumen_porcen.append(resumen2_porcen_valores)
        else:
            salida_resumen_porcen = resumen2_valores


    wb = xw.Book(xlFile)
    print()
    print()
    print('Exportando tablas')


    hoja_out = wb.sheets['ASIGNACION']
    hoja_out.clear_contents() 

    hoja_out.range('A1').options(index=True).value = salida_filas
    hoja_out.autofit()

    hoja_out = wb.sheets['RESUMEN']
    hoja_out.clear_contents() 
    hoja_out.range('A1').options(index=True).value = salida_resumen
    hoja_out.autofit()



    hoja_out = wb.sheets['RESUMEN %']
    hoja_out.clear_contents() 
    hoja_out.range('A1').options(index=True, NumberFormat = "0%").value = salida_resumen_porcen
    hoja_out.range('C2:R20').number_format = "0%" 
    hoja_out.autofit()



    # EXPANSION
    # hoja_out = wb.sheets['EXPANSION'] 
    # hoja_out.clear_contents() 
    # hoja_out.range('A1').options(index=True).value = DF_BINARIOS_SALIDA
    # hoja_out.autofit()


    # INTERCAMBIO
    hoja_out = wb.sheets['INTERCAMBIO'] 
    hoja_out.clear_contents() 
    hoja_out.range('A1').options(index=True).value = DF_INTERCAMBIO
    hoja_out.autofit()

    # BENEFICIO
    hoja_out = wb.sheets['BENEFICIO'] 
    hoja_out.clear_contents() 
    hoja_out.range('A1').options(index=True).value = BENEFICIO_M_FINAL
    hoja_out.autofit()


    # BARRAS 
    hoja_out = wb.sheets['PORCENTAJE BARRAS'] 
    hoja_out.clear_contents() 
    hoja_out.range('A1').options(index=True).value =  PORCENTAJEBARRAS_FINAL
    hoja_out.range('C2:R80').number_format = "0%" 
    hoja_out.autofit()



    # AREAS
    hoja_out = wb.sheets['PORCENTAJE AREAS'] 
    hoja_out.clear_contents() 
    hoja_out.range('A1').options(index=True).value = PORCENTAJEAREAS_FINAL
    hoja_out.range('C2:R80').number_format = "0%" 
    hoja_out.autofit()


    # ZONAS
    hoja_out = wb.sheets['PORCENTAJE ZONAS'] 
    hoja_out.clear_contents() 
    hoja_out.range('A1').options(index=True).value = PORCENTAJEZONAS_FINAL
    hoja_out.range('C2:R80').number_format = "0%" 
    hoja_out.autofit()


    wb.save()

