瀏覽代碼

Version 1

oscarleiva 5 年之前
父節點
當前提交
3767ac55e2
共有 87 個文件被更改,包括 1460 次插入627 次删除
  1. 4 0
      .vscode/settings.json
  2. 二進制
      __pycache__/presdespacho.cpython-38.pyc
  3. 二進制
      app.ico
  4. 0 0
      common/__init__.py
  5. 二進制
      common/__pycache__/__init__.cpython-37.pyc
  6. 二進制
      common/__pycache__/__init__.cpython-38.pyc
  7. 二進制
      common/__pycache__/data.cpython-37.pyc
  8. 二進制
      common/__pycache__/data.cpython-38.pyc
  9. 二進制
      common/__pycache__/exceptions.cpython-37.pyc
  10. 二進制
      common/__pycache__/exceptions.cpython-38.pyc
  11. 二進制
      common/__pycache__/log.cpython-37.pyc
  12. 二進制
      common/__pycache__/log.cpython-38.pyc
  13. 二進制
      common/__pycache__/redirect.cpython-38.pyc
  14. 26 0
      common/data.py
  15. 27 0
      common/exceptions.py
  16. 28 0
      common/log.py
  17. 二進制
      ejemplos/predespacho2112/predespacho_2112.xlsx
  18. 二進制
      ejemplos/predespacho2112/predespacho_2112_results.xlsx
  19. 二進制
      ejemplos/predespacho2112/~$predespacho_2112.xlsx
  20. 二進制
      ejemplos/predespacho2112/~$resultados_predespacho_0.xlsx
  21. 二進制
      ejemplos/predespacho2112/~$resultados_predespacho_24h.xlsx
  22. 0 0
      gui/__init__.py
  23. 二進制
      gui/__pycache__/__init__.cpython-38.pyc
  24. 二進制
      gui/__pycache__/console.cpython-38.pyc
  25. 二進制
      gui/__pycache__/forms.cpython-38.pyc
  26. 二進制
      gui/__pycache__/gui.cpython-38.pyc
  27. 二進制
      gui/__pycache__/splash.cpython-38.pyc
  28. 二進制
      gui/__pycache__/status.cpython-38.pyc
  29. 69 0
      gui/console.py
  30. 129 0
      gui/forms.py
  31. 132 0
      gui/gui.py
  32. 二進制
      gui/img/icons/icons8-abrir-carpeta-16.png
  33. 二進制
      gui/img/icons/icons8-apoyo-16.png
  34. 二進制
      gui/img/icons/icons8-archivo-16.png
  35. 二進制
      gui/img/icons/icons8-bloquear-16.png
  36. 二進制
      gui/img/icons/icons8-cancelar-16.png
  37. 二進制
      gui/img/icons/icons8-cancelar-2-16.png
  38. 二進制
      gui/img/icons/icons8-carpeta-16.png
  39. 二進制
      gui/img/icons/icons8-casa-16.png
  40. 二進制
      gui/img/icons/icons8-comprobado-16.png
  41. 二進制
      gui/img/icons/icons8-desbloquear-16.png
  42. 二進制
      gui/img/icons/icons8-documento-16.png
  43. 二進制
      gui/img/icons/icons8-eliminar-16-2.png
  44. 二進制
      gui/img/icons/icons8-eliminar-16.png
  45. 二進制
      gui/img/icons/icons8-información-16.png
  46. 二進制
      gui/img/icons/icons8-play-16.png
  47. 二進制
      gui/img/icons/icons8-prismáticos-16.png
  48. 二進制
      gui/img/icons/icons8-servicios-16.png
  49. 二進制
      gui/img/splash.png
  50. 47 0
      gui/splash.py
  51. 37 0
      gui/status.py
  52. 12 12
      install.bat
  53. 22 2
      install_copy_files.py
  54. 14 613
      main.py
  55. 0 0
      manuales/Manual Modelo_Predespacho_24h.docx
  56. 0 0
      manuales/Manual Modelo_Predespacho_24h.pdf
  57. 0 0
      manuales/__pycache__/predespacho_24h.cpython-37.pyc
  58. 0 0
      manuales/~$nual Modelo_Predespacho_24h.docx
  59. 二進制
      mc3.exe
  60. 二進制
      mct/__pycache__/__init__.cpython-38.pyc
  61. 二進制
      mct/__pycache__/makeMCT.cpython-38.pyc
  62. 685 0
      presdespacho.py
  63. 1 0
      qhandler/__init__.py
  64. 二進制
      qhandler/__pycache__/__init__.cpython-37.pyc
  65. 二進制
      qhandler/__pycache__/__init__.cpython-38.pyc
  66. 二進制
      qhandler/__pycache__/queuehandler.cpython-37.pyc
  67. 二進制
      qhandler/__pycache__/queuehandler.cpython-38.pyc
  68. 22 0
      qhandler/queuehandler.py
  69. 二進制
      red/__pycache__/__init__.cpython-38.pyc
  70. 二進制
      red/__pycache__/create.cpython-38.pyc
  71. 二進制
      red/__pycache__/create1.cpython-38.pyc
  72. 二進制
      red/__pycache__/makeBdc.cpython-38.pyc
  73. 二進制
      red/__pycache__/read.cpython-38.pyc
  74. 2 0
      requirements.txt
  75. 5 0
      run.bat
  76. 120 0
      spr.bat
  77. 0 0
      spr/__init__.py
  78. 二進制
      spr/__pycache__/__init__.cpython-38.pyc
  79. 二進制
      spr/__pycache__/runspr.cpython-38.pyc
  80. 二進制
      spr/__pycache__/runthread.cpython-38.pyc
  81. 34 0
      spr/runspr.py
  82. 33 0
      spr/runthread.py
  83. 二進制
      utils/__pycache__/__init__.cpython-38.pyc
  84. 二進制
      utils/__pycache__/arr2dict.cpython-38.pyc
  85. 二進制
      utils/__pycache__/idx_brch.cpython-38.pyc
  86. 二進制
      utils/__pycache__/solver_checker.cpython-38.pyc
  87. 11 0
      utils/solver_checker.py

+ 4 - 0
.vscode/settings.json

@@ -0,0 +1,4 @@
+{
+    "python.pythonPath": "mc3\\python.exe",
+    "git.ignoreLimitWarning": true
+}

二進制
__pycache__/presdespacho.cpython-38.pyc


二進制
app.ico


+ 0 - 0
common/__init__.py


二進制
common/__pycache__/__init__.cpython-37.pyc


二進制
common/__pycache__/__init__.cpython-38.pyc


二進制
common/__pycache__/data.cpython-37.pyc


二進制
common/__pycache__/data.cpython-38.pyc


二進制
common/__pycache__/exceptions.cpython-37.pyc


二進制
common/__pycache__/exceptions.cpython-38.pyc


二進制
common/__pycache__/log.cpython-37.pyc


二進制
common/__pycache__/log.cpython-38.pyc


二進制
common/__pycache__/redirect.cpython-38.pyc


+ 26 - 0
common/data.py

@@ -0,0 +1,26 @@
+'''
+    Application Data functions
+'''
+
+import os
+
+__APPFOLDER = os.path.expandvars(r'%LOCALAPPDATA%\Merelec\spr')
+__CACHE = f'{__APPFOLDER}\cache'
+__DATA = f'{__APPFOLDER}\data'
+__CONFIG = f'{__APPFOLDER}\config'
+
+APPDIRS = {
+    'APPFOLDER': __APPFOLDER,
+    'CACHE': __CACHE,
+    'DATA': __DATA,
+    'CONFIG': __CONFIG
+}
+
+
+def check_appdata_folders():
+    [create_dir(v) for (k, v) in APPDIRS.items()]
+
+
+def create_dir(directory):
+    if not os.path.exists(directory):
+        os.makedirs(directory)

+ 27 - 0
common/exceptions.py

@@ -0,0 +1,27 @@
+class ExcelFileError(Exception):
+    """Exception raised for error in the input Excel File.
+
+    Attributes:
+        file -- input Excel file
+    """
+
+    def __init__(self, file, message="El archivo no es valido"):
+        self.file = file
+        self.message = message
+        super().__init__(self.message)
+
+    def __str__(self):
+        return f'{self.file} -> {self.message}'
+
+
+class SolverNotFoundError(Exception):
+    """Exception raised if solver not found.
+
+    """
+
+    def __init__(self, message="No se encontró el solver en el PATH"):
+        self.message = message
+        super().__init__(self.message)
+
+    def __str__(self):
+        return self.message

+ 28 - 0
common/log.py

@@ -0,0 +1,28 @@
+#
+# Utility classes for working with the logger
+#
+import sys
+import logging
+from logging.handlers import RotatingFileHandler
+
+_fh = RotatingFileHandler(
+    'log/simsdt_app_monitor.log', maxBytes=1024*50, backupCount=10, encoding='utf-8')
+_fmt = logging.Formatter(
+    '%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%dT%H:%M:%S')
+_fh.setFormatter(_fmt)
+_fh.setLevel(logging.INFO)
+
+logger = logging.getLogger('spr')
+logger.addHandler(_fh)
+logger.setLevel(logging.INFO)
+
+
+class NullStream:
+    """
+    A file like class that writes nothing
+    """
+
+    def close(self): pass
+    def flush(self): pass
+    def write(self, str): pass
+    def writelines(self, sequence): pass

二進制
ejemplos/predespacho2112/predespacho_2112.xlsx


二進制
ejemplos/predespacho2112/predespacho_2112_results.xlsx


二進制
ejemplos/predespacho2112/~$predespacho_2112.xlsx


二進制
ejemplos/predespacho2112/~$resultados_predespacho_0.xlsx


二進制
ejemplos/predespacho2112/~$resultados_predespacho_24h.xlsx


+ 0 - 0
gui/__init__.py


二進制
gui/__pycache__/__init__.cpython-38.pyc


二進制
gui/__pycache__/console.cpython-38.pyc


二進制
gui/__pycache__/forms.cpython-38.pyc


二進制
gui/__pycache__/gui.cpython-38.pyc


二進制
gui/__pycache__/splash.cpython-38.pyc


二進制
gui/__pycache__/status.cpython-38.pyc


+ 69 - 0
gui/console.py

@@ -0,0 +1,69 @@
+import queue
+import tkinter as tk
+from tkinter import E, N, S, W, ttk
+from tkinter.scrolledtext import ScrolledText
+
+from PIL import Image, ImageTk
+
+
+class ConsoleUi:
+    """Poll messages from a logging queue and display them in a scrolled text
+    widget"""
+
+    def __init__(self, frame, q, qh):
+        self.frame = frame
+        self.log_queue = q
+        self.queue_handler = qh
+
+        trash_icon = Image.open('gui/img/icons/icons8-eliminar-16.png')
+        self.trash_icon = ImageTk.PhotoImage(trash_icon)
+        # Create a ScrolledText wdiget
+        self.scrolled_text = ScrolledText(frame, state='disabled', height=25)
+        self.scrolled_text.grid(row=0, column=0, sticky=(N, S, W, E))
+        self.clear = ttk.Button(frame, text='Limpiar Log',
+                                command=self.clear_console,
+                                image=self.trash_icon,
+                                compoun='right')
+        self.clear.grid(row=1, column=0, sticky=E, pady=(5, 5))
+        # Font config
+        self.scrolled_text.configure(font='TkFixedFont')
+        self.scrolled_text.tag_config('INFO', foreground='black')
+        self.scrolled_text.tag_config('DEBUG', foreground='gray')
+        self.scrolled_text.tag_config('WARNING', foreground='orange')
+        self.scrolled_text.tag_config('ERROR', foreground='red')
+        self.scrolled_text.tag_config(
+            'CRITICAL', foreground='red', underline=1)
+        # Create a logging handler using a queue
+
+        # self.queue_handler = QueueHandler(self.log_queue)
+        # formatter = logging.Formatter(
+        #     '%(asctime)s: %(message)s', datefmt='%Y-%m-%dT%H:%M:%S')
+        # self.queue_handler.setFormatter(formatter)
+        # # self.queue_handler.setLevel(logging.INFO)
+        # logger.addHandler(self.queue_handler)
+        # Start polling messages from the queue
+        self.frame.after(100, self.poll_log_queue)
+
+    def display(self, record):
+        msg = self.queue_handler.format(record)
+        self.scrolled_text.configure(state='normal')
+        self.scrolled_text.insert(tk.END, msg + '\n', record.levelname)
+        self.scrolled_text.configure(state='disabled')
+        # Autoscroll to the bottom
+        self.scrolled_text.yview(tk.END)
+
+    def poll_log_queue(self):
+        # Check every 100ms if there is a new message in the queue to display
+        while True:
+            try:
+                record = self.log_queue.get(block=False)
+            except queue.Empty:
+                break
+            else:
+                self.display(record)
+        self.frame.after(100, self.poll_log_queue)
+
+    def clear_console(self):
+        self.scrolled_text.configure(state='normal')
+        self.scrolled_text.delete(1.0, tk.END)
+        self.scrolled_text.configure(state='disabled')

+ 129 - 0
gui/forms.py

@@ -0,0 +1,129 @@
+
+import logging
+import tkinter as tk
+from tkinter import E, W, filedialog, ttk
+
+from PIL import Image, ImageTk
+
+from utils.solver_checker import check_solver
+
+from spr.runthread import RunSprThread
+
+main_logger = logging.getLogger('spr')
+
+class FormUi:
+
+    runspr_thread = None
+
+    def __init__(self, frame, q):
+        self.frame = frame
+        self.q = q
+        image = Image.open('gui/img/icons/icons8-play-16.png')
+        self.photo = ImageTk.PhotoImage(image)
+
+        opfile = Image.open('gui/img/icons/icons8-abrir-carpeta-16.png')
+        self.opfile = ImageTk.PhotoImage(opfile)
+
+        # Add a text field for file path
+        self.file_path = tk.StringVar()
+        ttk.Label(self.frame, text='Archivo:').grid(
+            column=0, row=0, sticky=W, pady=(5, 5), padx=(0, 10))
+        self.entry = ttk.Entry(self.frame, textvariable=self.file_path,
+                               width=50)
+        self.entry.grid(column=1, row=0, sticky=(W, E), pady=(5, 5))
+
+        
+        
+        self.button = ttk.Button(
+            self.frame, image=self.opfile, compound='center',
+            command=self.open_file_dialog, width=3)
+        self.button.grid(column=2, row=0, sticky=W)
+
+
+
+        self.all_day = tk.IntVar()
+        self.all_day_cb = ttk.Checkbutton(self.frame, text="Ejecutar 24 períodos", variable=self.all_day, command=self.chkbox_state)
+        self.all_day_cb.state(['selected'])
+        self.all_day.set(1)
+        self.all_day_cb.grid(column=1, row=1, sticky=W)
+
+
+
+
+        periodos = [*range(0,24)]
+        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(23)
+        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,
+                                     compound="right", text='Ejecutar',
+                                     command=self.run)
+        self.button_run.grid(column=1, row=3, sticky=W)
+
+        
+
+    def open_file_dialog(self):
+        # Open file dialog
+        try:
+            file = filedialog.askopenfilename(
+                filetypes=[('Excel', '.xlsx')],
+                title='Seleccione un archivo de predespacho...')
+        except Exception as e:
+            main_logger.error(e)
+            self.file_path.set('')
+        else:
+            main_logger.info(f'Archivo seleccionado: {file}')
+            self.file_path.set(file)
+
+    def chkbox_state(self):
+        if self.all_day_cb.instate(['selected']):
+            self.period_combo.configure(state='disabled')
+            self.period_combo.current(0)
+            self.period_combo.set(23)
+        else:
+            self.period_combo.configure(state='normal')
+
+    def run(self):
+           
+        try:
+            check_solver()
+
+            if not self.file_path.get():
+                return
+
+            inputfile = self.file_path.get()
+            all_day = self.all_day.get()
+            if all_day == 1:
+                all_day = True
+            else:
+                all_day = False
+
+            period = self.period_combo.get()
+
+            
+            self.button_run.configure(state='disabled')
+
+            self.runspr_thread = RunSprThread(args=(inputfile,int(period),all_day))
+            self.runspr_thread.start()
+
+            self.check_thread()
+
+        except Exception as e:
+            main_logger.error(e)
+
+            return
+
+    def check_thread(self):
+
+        if not self.runspr_thread.is_alive():
+            self.button_run.configure(state='normal')
+            self.q.put(False)
+        else:
+            self.q.put(True)
+            self.frame.after(100, self.check_thread)

+ 132 - 0
gui/gui.py

@@ -0,0 +1,132 @@
+import logging
+import queue
+import signal
+import tkinter as tk
+from tkinter import filedialog, messagebox, HORIZONTAL, VERTICAL, ttk
+from gui.splash import Splash
+from gui.forms import FormUi
+from gui.console import ConsoleUi
+from gui.status import StatusUi
+
+from qhandler import QueueHandler
+
+
+logger = logging.getLogger('spr')
+
+
+def show_error(msg):
+    messagebox.showerror(
+        "Error del Sistema", msg)
+    sys.exit()
+
+
+def get_file():
+    file = filedialog.askopenfilename(
+        filetypes=[('Excel', '.xlsx')], title='Seleccione un archivo de subasta...')
+
+    if not file:
+        messagebox.showerror(
+            "Error - Selección de Archivo", "Debe seleccionar un archivo para ejecutar la subasta!!")
+        sys.exit()
+
+
+def center(win):
+    """
+    centers a tkinter window
+    :param win: the root or Toplevel window to center
+    """
+    win.update_idletasks()
+    width = win.winfo_width()
+    frm_width = win.winfo_rootx() - win.winfo_x()
+    win_width = width + 2 * frm_width
+    height = win.winfo_height()
+    titlebar_height = win.winfo_rooty() - win.winfo_y()
+    win_height = height + titlebar_height + frm_width
+    x = win.winfo_screenwidth() // 2 - win_width // 2
+    y = win.winfo_screenheight() // 2 - win_height // 2
+    win.geometry('{}x{}+{}+{}'.format(width, height, x, y))
+    win.deiconify()
+
+
+class App:
+
+    def __init__(self, root):
+        self.root = root
+
+        Splash(self.root)
+
+        # Queue a nivel de App para manejar el progress bar
+        pbqueue = queue.Queue()
+        log_queue = queue.Queue()
+
+        root.title('Simulación Predespacho del MER')
+        root.iconbitmap("app.ico")
+
+        self.queue_handler = QueueHandler(log_queue)
+        formatter = logging.Formatter(
+            '%(asctime)s: %(message)s', datefmt='%Y-%m-%dT%H:%M:%S')
+        self.queue_handler.setFormatter(formatter)
+        # self.queue_handler.setLevel(logging.INFO)
+        logger.addHandler(self.queue_handler)
+
+        w = ttk.Notebook(self.root)
+        w.grid(row=1, column=0, sticky="nsew",
+               padx=10, pady=(0, 10))
+
+        tab_exec = ttk.Frame(w)
+
+        # Create the panes and frames
+        vertical_pane = ttk.PanedWindow(
+            tab_exec, orient=VERTICAL)
+        vertical_pane.grid(row=0, column=0, sticky="nsew", padx=10, pady=10)
+
+        main_title = ttk.Label(
+            self.root,
+            text='Simulación del Predespacho del MER',
+            font=('', '20', 'bold'))
+        main_title.grid(row=0, column=0, pady=10)
+
+        horizontal_pane = ttk.PanedWindow(vertical_pane, orient=HORIZONTAL)
+        vertical_pane.add(horizontal_pane, weight=1)
+
+        form_frame = ttk.Labelframe(
+            horizontal_pane, text="Configuración", padding=(5, 5))
+        form_frame.columnconfigure(1, weight=1)
+        horizontal_pane.add(form_frame, weight=1)
+
+        console_frame = ttk.Labelframe(
+            horizontal_pane, text="Consola", padding=(5, 5))
+        console_frame.columnconfigure(0, weight=1)
+        console_frame.rowconfigure(0, weight=1)
+
+        horizontal_pane.add(console_frame, weight=1)
+        status_frame = ttk.Labelframe(
+            vertical_pane, text="Estado", padding=(5, 5))
+        vertical_pane.add(status_frame, weight=0)
+        # Initialize all frames
+        self.form = FormUi(form_frame, pbqueue)
+        self.console = ConsoleUi(console_frame, log_queue, self.queue_handler)
+        self.status = StatusUi(status_frame, pbqueue)
+
+        w.add(tab_exec, text='Ejecución')
+
+        # bindings
+
+        self.root.protocol('WM_DELETE_WINDOW', self.quit)
+        self.root.bind('<Control-q>', self.quit)
+        signal.signal(signal.SIGINT, self.quit)
+
+        center(self.root)
+
+    def quit(self, *args):
+
+        msg = 'Se esta ejecutando un proceso de optimización\n\n'
+        msg += '¿Desea salir de la aplicación?'
+
+        if self.form.runspr_thread and self.form.runspr_thread.is_alive():
+            if messagebox.askokcancel("Salir de la Simulación", msg):
+                logger.info('Cerrando aplicacion...')
+                self.form.runspr_thread.stop()
+                self.root.destroy()
+        else:
+            self.root.destroy()

二進制
gui/img/icons/icons8-abrir-carpeta-16.png


二進制
gui/img/icons/icons8-apoyo-16.png


二進制
gui/img/icons/icons8-archivo-16.png


二進制
gui/img/icons/icons8-bloquear-16.png


二進制
gui/img/icons/icons8-cancelar-16.png


二進制
gui/img/icons/icons8-cancelar-2-16.png


二進制
gui/img/icons/icons8-carpeta-16.png


二進制
gui/img/icons/icons8-casa-16.png


二進制
gui/img/icons/icons8-comprobado-16.png


二進制
gui/img/icons/icons8-desbloquear-16.png


二進制
gui/img/icons/icons8-documento-16.png


二進制
gui/img/icons/icons8-eliminar-16-2.png


二進制
gui/img/icons/icons8-eliminar-16.png


二進制
gui/img/icons/icons8-información-16.png


二進制
gui/img/icons/icons8-play-16.png


二進制
gui/img/icons/icons8-prismáticos-16.png


二進制
gui/img/icons/icons8-servicios-16.png


二進制
gui/img/splash.png


+ 47 - 0
gui/splash.py

@@ -0,0 +1,47 @@
+import time
+import tkinter as tk
+
+from PIL import Image, ImageTk
+
+
+class Splash(tk.Toplevel):
+    def __init__(self, master=None, **kw):
+        tk.Toplevel.__init__(self, master=master, **kw)
+        self._root = master
+        _image = Image.open('gui/img/splash.png')
+        self._image = ImageTk.PhotoImage(_image)
+
+        self._root.withdraw()
+
+        tk.Label(self, image=self._image, relief='flat').pack()
+
+        self.center()
+        self.lift()
+        self.attributes('-topmost', True)
+        self.attributes('-topmost', False)
+
+        self.overrideredirect(1)
+        self.update()
+
+        time.sleep(3)
+
+        self.destroy()
+
+        self._root.deiconify()
+
+    def center(self):
+        """
+        centers a tkinter window
+        :param self: the root or Toplevel window to center
+        """
+        self.update_idletasks()
+        width = self.winfo_width()
+        frm_width = self.winfo_rootx() - self.winfo_x()
+        win_width = width + 2 * frm_width
+        height = self.winfo_height()
+        titlebar_height = self.winfo_rooty() - self.winfo_y()
+        win_height = height + titlebar_height + frm_width
+        x = self.winfo_screenwidth() // 2 - win_width // 2
+        y = self.winfo_screenheight() // 2 - win_height // 2
+        self.geometry('{}x{}+{}+{}'.format(width, height, x, y))
+        self.deiconify()

+ 37 - 0
gui/status.py

@@ -0,0 +1,37 @@
+import queue
+import tkinter as tk
+from tkinter import ttk
+
+
+class StatusUi:
+
+    def __init__(self, frame, q):
+        self.q = q
+        self.frame = frame
+        self.pb_max = 100
+        # ttk.Label(self.frame, text='This is just an example of a third frame').grid(
+        #     column=0, row=1, sticky=W)
+        self.progress_bar = ttk.Progressbar(
+            self.frame, mode='determinate')
+        self.progress_bar.pack(expand=True, fill=tk.X, side=tk.TOP)
+
+        self.frame.after(100, self.check_q)
+
+    def check_q(self):
+        # Check every 100ms if there is a new message in the queue to display
+        while True:
+            try:
+                record = self.q.get(block=False)
+            except queue.Empty:
+                break
+            else:
+                if record:
+                    step = 1
+                    self.progress_bar.step(step)
+                    if step >= self.pb_max:
+                        step = 1
+                    else:
+                        step += 1
+                else:
+                    self.progress_bar.config(value=0)
+        self.frame.after(100, self.check_q)

+ 12 - 12
install.bat

@@ -1,34 +1,33 @@
 @echo off
 
-REM echo Instalando Python y paquetes necesarios
-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 Instalando Python y paquetes necesarios
+echo Descargando Python...
+powershell -command "& { (New-Object Net.WebClient).DownloadFile('https://repo.anaconda.com/miniconda/Miniconda3-latest-Windows-x86_64.exe', 'mc3.exe') }"
 
-REM echo Instalando Python
-REM start /wait "" mc3.exe /InstallationType=JustMe /AddToPath=0 /RegisterPython=0 /NoRegistry=1 /S /D=%LOCALAPPDATA%\Merelec\spr\mc3
+echo Instalando Python
+start /wait "" mc3.exe /InstallationType=JustMe /AddToPath=0 /RegisterPython=0 /NoRegistry=1 /S /D=%LOCALAPPDATA%\Merelec\spr\mc3
 
 echo Verificando la version de Python
 
-REM %LOCALAPPDATA%\Merelec\spr\mc3\python.exe --version
+%LOCALAPPDATA%\Merelec\spr\mc3\python.exe --version
 
-REM %LOCALAPPDATA%\Merelec\spr\mc3\python.exe install_copy_files.py
+%LOCALAPPDATA%\Merelec\spr\mc3\python.exe install_copy_files.py
 
-REM Seteando variables para resolver el problema ssl
+Seteando variables para resolver el problema ssl
 echo
 echo
-echo seteando el PATH
+echo Seteando variables de entorno...
 
 SET PATH=%PATH%;%LOCALAPPDATA%\Merelec\spr\mc3;%LOCALAPPDATA%\Merelec\spr\mc3\Scripts;%LOCALAPPDATA%\Merelec\spr\mc3\Library;%LOCALAPPDATA%\Merelec\spr\mc3\Library\bin
 
-
 cd %LOCALAPPDATA%\Merelec\spr
-echo Actualizando pip
+
+echo Actualizando la version de pip
 
 %LOCALAPPDATA%\Merelec\spr\mc3\python.exe -m pip install --upgrade pip
 
 echo Fin de actualización de pip
 
-
 echo Instalando paquetes necesarios
 
 @echo on
@@ -41,4 +40,5 @@ set ipopt=%LOCALAPPDATA%\Merelec\spr\ipopt
 echo Verificando instalación de python y Ipopt
 
 ipopt --version
+
 pause

+ 22 - 2
install_copy_files.py

@@ -2,7 +2,11 @@ import os
 import sys
 import shutil
 
-unrequired_files = ("install.py", "mc3.exe", "miniconda_install.bat", ".git")
+import winshell
+from win32com.client import Dispatch
+
+unrequired_files = ("install.bat", "install_copy_files.py",
+                    "mc3.exe", "miniconda_install.bat", ".git")
 
 
 def install():
@@ -18,9 +22,25 @@ def install():
         print("Copiando archivos del sistema")
         shutil.copytree(os.curdir, idir,
                         ignore=shutil.ignore_patterns(
-                            "install.py", "mc3.exe", "miniconda_install.bat", ".git"),
+                            "install.bat", "install_copy_files.py", "mc3.exe", "miniconda_install.bat", ".git"),
                         dirs_exist_ok=True)
 
+    # creates shortcut
+    desktop = winshell.desktop()
+
+    path = os.path.join(desktop, "Predespacho Regional.lnk")
+    target = os.path.join(
+        os.environ["LOCALAPPDATA"], "Merelec", "spr", "run.bat")
+    wDir = desktop
+    icon = os.path.join(os.environ["LOCALAPPDATA"],
+                        "Merelec", "spr", "app.ico")
+    shell = Dispatch('WScript.Shell')
+    shortcut = shell.CreateShortCut(path)
+    shortcut.Targetpath = target
+    shortcut.WorkingDirectory = wDir
+    shortcut.IconLocation = icon
+    shortcut.save()
+
 
 if __name__ == "__main__":
     install()

+ 14 - 613
main.py

@@ -1,619 +1,20 @@
-from __future__ import division
-from pyomo.environ import *
-from red.read import excel2net
-from red.create import *
-from red.create1 import *
-from red.makeBdc import makeBdc
-from utils.arr2dict import arr2dict
-from pyomo.environ import SolverFactory
-from pyomo.kernel import value
-from numpy import zeros, array
-from pandas import DataFrame, ExcelWriter
-from mct.makeMCT import linmct, readmct, set_dir_flujo
-from os import path
 
+import tkinter as tk
+from gui.gui import App
+from common import data, log
+import sys
 
-def setmodel(file):
 
-    print("{:=^100}".format(""))
-    print("{:^100}".format(" Modelo de Predespacho Regional"))
-    print("{:^100}".format(" Mercados Eléctricos de Centroamérica (c) 2020 "))
-    print("{:=^100}".format(""))
-    # ============================================================================
-    # Importación de datos desde archivo Excel
-    # ============================================================================
-
-    # Parametros de la linea
-    print("Inicio del Script de Predespacho")
-    print("Leyendo información de red...")
-    net = excel2net(file)
-    bus = setbus(net)  # Nodos
-    branch = setbranch(net, bus)  # Set lineas
-    bu = branch[:, 5]  # potenica max de la linea
-    bl = branch[:, 6]  # potenica min de la linea
-    xc = branch[:, 3]  # Reactancia de la linea
-    rc = branch[:, 4]  # Resistencia de la linea
-    nb = bus.shape[0]  # Numero de nodos
-    nbr = branch.shape[0]  # Numero de lineas
-    A = makeBdc(bus, branch)  # Matriz incidente
-    brnames = branchnames(bus, branch)  # Nombre de las lineas
-    inc = A.toarray()*-1
-
-    # Lineas para límites de MCT
-    br_t = brnames['Total'].to_numpy()
-    lin_mct = linmct(br_t)
-    dirf = set_dir_flujo()
-    mct = readmct(file)
-
-    # Informacion de los despachos nacionales
-    dg_t = read_D_G(file)
-
-    # Ofertas de todos los periodos
-    ex_cnfff_t = readofertas_cnfffs(file)
-    ex_ooi_t = readofertas_oois(file)
-    ex_oor_t = readofertas_oors(file)
-    ex_cf_t = readofertas_cfs(file)
-
-    # Dataframe para almacenar la informacion de cada predespacho
-    flujos_t = DataFrame()
-    iep_t = DataFrame()
-    pon_t = DataFrame()
-    result_foo_i_t = DataFrame()
-    result_foo_r_t = DataFrame()
-    result_fof_t = DataFrame()
-    result_foff_t = DataFrame()
-    foo_ret_iny_t = DataFrame()
-    # El range del for se modifica dependiendo los periodos que se quieren correr.
-    for PERIODO in range(0, 24):
-
-        print("Leyendo información de los despacho nacionales. Periodo: " + str(PERIODO))
-        # Dependiendo de los valores de la columna periodo del df son los valores que toma
-        dg = dg_t[dg_t.periodo.isin([PERIODO])]
-        # Resetea valores de ordenamiento del DF
-        dg.reset_index(drop=True, inplace=True)
-        # Ordena los valores que tiene segun los nodos de rtr
-        dg_n = set_dgnacional(bus, dg)
-
-        print("Leyendo información de ofertas. Periodo: " + str(PERIODO))
-        # Funcion leer contratos no firmes fisicos flexibles
-        # Dependiendo de los valores de la columna periodo del df son los valores que toma
-        ex_cnfff = ex_cnfff_t[ex_cnfff_t.periodo.isin([PERIODO])]
-        # Resetea valores de ordenamiento del DF
-        ex_cnfff.reset_index(drop=True, inplace=True)
-        # Energia declarada con respecto al nodo
-        vnfff_ed = setvariable(ex_cnfff['energía_dec'])
-        # Magnitud de energia ofertada -flexibilizacion
-        vnfff_m_i = setvariable_s(
-            ex_cnfff[['magnitud_i1', 'magnitud_i2', 'magnitud_i3', 'magnitud_i4', 'magnitud_i5']])
-        vnfff_m_r = setvariable_s(
-            ex_cnfff[['magnitud_r1', 'magnitud_r2', 'magnitud_r3', 'magnitud_r4', 'magnitud_r5']])
-        vnfff_m_cvt = setvariable_s(
-            ex_cnfff[['magnitud_cvt1', 'magnitud_cvt2', 'magnitud_cvt3', 'magnitud_cvt4', 'magnitud_cvt5']])
-        # Precio de la ofertas de inyeccion
-        p_cnfffi = setvariable_s(
-            ex_cnfff[['precio_i1', 'precio_i2', 'precio_i3', 'precio_i4', 'precio_i5']])
-        # Precio de la ofertas de retiro
-        p_cnfffr = setvariable_s(
-            ex_cnfff[['precio_r1', 'precio_r2', 'precio_r3', 'precio_r4', 'precio_r5']])
-        # Precio de la ofertas de inyeccion
-        p_cnfffcvt = setvariable_s(
-            ex_cnfff[['precio_cvt1', 'precio_cvt2', 'precio_cvt3', 'precio_cvt4', 'precio_cvt5']])
-        # Precio de la ofertas de inyeccion
-        k_cnfffcvt = setvariable(ex_cnfff['k'])
-        NCFF = ex_cnfff.shape[0]  # Numero de contratos firmes
-        var_bin_cnfffr = MATRIZ_VNFFF_R(bus, ex_cnfff)
-        var_bin_cnfffi = MATRIZ_VNFFF_I(bus, ex_cnfff)
-        dem = setvariable(dg_n['Demanda'])
-        gen = setvariable(dg_n['Generacion'])
-
-        # Funcion leer parametros oferta de oportunidad inyeccion
-        # Dependiendo de los valores de la columna periodo del df son los valores que toma
-        ex_ooi = ex_ooi_t[ex_ooi_t.periodo.isin([PERIODO])]
-        # Resetea valores de ordenamiento del DF
-        ex_ooi.reset_index(drop=True, inplace=True)
-        vooi_m = setvariable_s(ex_ooi[['magnitud_ooi1', 'magnitud_ooi2', 'magnitud_ooi3',
-                                       'magnitud_ooi4', 'magnitud_ooi5']])  # Ofertas con respecto al nodo
-        p_ooi = setvariable_s(ex_ooi[['precio_ooi1', 'precio_ooi2', 'precio_ooi3',
-                                      'precio_ooi4', 'precio_ooi5']])  # Precio de la ofertas
-        NOI = ex_ooi.shape[0]  # Numero de ofertas de inyeccion
-        var_bin_ooi = MATRIZ_OOI(bus, ex_ooi)
-
-        # Funcion leer parametros oferta de oportunidad retiro
-        ex_oor = ex_oor_t[ex_oor_t.periodo.isin([PERIODO])]
-        # Resetea valores de ordenamiento del DF
-        ex_oor.reset_index(drop=True, inplace=True)
-        voor_m = setvariable_s(ex_oor[['magnitud_oor1', 'magnitud_oor2', 'magnitud_oor3',
-                                       'magnitud_oor4', 'magnitud_oor5']])  # Ofertas con respecto al nodo
-        # Precio de la ofertas - flexibilizacion
-        p_oor = setvariable_s(
-            ex_oor[['precio_oor1', 'precio_oor2', 'precio_oor3', 'precio_oor4', 'precio_oor5']])
-        NOR = ex_oor.shape[0]  # Numero de ofertas de retiro
-        var_bin_oor = MATRIZ_OOR(bus, ex_oor)
-
-        # Funcion leer parametros contratos firmes
-        # Dependiendo de los valores de la columna periodo del df son los valores que toma
-        ex_cf = ex_cf_t[ex_cf_t.periodo.isin([PERIODO])]
-        # Resetea valores de ordenamiento del DF
-        ex_cf.reset_index(drop=True, inplace=True)
-        # Energia declarada con respecto al nodo
-        vcf_ed = setvariable(ex_cf['energía_dec'])
-        # Potencia requerida con respecto al nodo
-        vcf_pr = setvariable(ex_cf['potencia_req'])
-        # Magnitud de energia ofertada -flexibilizacion
-        vcf_m = setvariable_s(
-            ex_cf[['magnitu_cf1', 'magnitu_cf2', 'magnitu_cf3', 'magnitu_cf4', 'magnitu_cf5']])
-        # Precio de la ofertas
-        vcf_p = setvariable_s(
-            ex_cf[['precio_cf1', 'precio_cf2', 'precio_cf3', 'precio_cf4', 'precio_cf5']])
-        NCF = ex_cf.shape[0]  # Numero de contratos firmes
-        var_bin_cfr = MATRIZ_CFR(bus, ex_cf)
-        var_bin_cfi = MATRIZ_CFI(bus, ex_cf)
-
-        # Inicio del modelo de optimización
-        model = ConcreteModel()
-
-        # sets
-        model.i = Set(initialize=range(0, nb))  # numero de nodos
-        model.c = Set(initialize=range(0, nbr))  # Numero de lineas
-        # numero de ofertas de oportuniddad retiro
-        model.OR = Set(initialize=range(0, NOR))
-        # numero de ofertas de oportunidad inyeccion
-        model.OI = Set(initialize=range(0, NOI))
-        # numero de ofertas de CNFFF
-        model.CFF = Set(initialize=range(0, NCFF))
-        # numero de ofertas de contratos firmes
-        model.CF = Set(initialize=range(0, NCF))
-        model.s = Set(initialize=range(0, 5))  # Numero de bloques
-        model.inter = Set(initialize=lin_mct.keys())  # Interconexiones
-        # Sentidos de interconexiones
-        model.sen = Set(initialize=['sn', 'ns'])
-        model.per = Set(initialize=range(0, 24))  # numero de periodos
-
-        # Parametros
-        # Parametros de la red
-        model.rtmw_min = Param(model.c, initialize=dict(enumerate(bl)))
-        model.rtmw_max = Param(model.c, initialize=dict(enumerate(bu)))
-        model.Inc = Param(model.c, model.i, initialize=arr2dict(inc))
-        model.Xc = Param(model.c, initialize=dict(enumerate(xc)))
-        model.Rc = Param(model.c, initialize=dict(enumerate(rc)))
-
-        # Parametros de los predespachos nacionales
-        model.D = Param(model.i, initialize=dict(enumerate(dem)))
-        model.G = Param(model.i, initialize=dict(enumerate(gen)))
-
-        # Ofertas de oportunidad
-        # Oferta de oportunidad de retiro
-        # Oferta bloques 1
-        model.fr = Param(model.OR, model.s, initialize=arr2dict(p_oor))
-        model.pr_ofertado = Param(model.OR, model.s, initialize=arr2dict(
-            voor_m))  # Magnitud de la oferta MW-h
-        model.bin_pr = Param(
-            model.i, model.OR, initialize=arr2dict(var_bin_oor))
-
-        # Oferta de oportunidad de inyeccion
-        # Precio de bloques - Oferta de oportunidad de inyeccion
-        model.fi = Param(model.OI, model.s, initialize=arr2dict(p_ooi))
-        model.pi_ofertado = Param(model.OI, model.s, initialize=arr2dict(
-            vooi_m))  # Magnitud de la oferta MW-h
-        model.bin_pi = Param(
-            model.i, model.OI, initialize=arr2dict(var_bin_ooi))
-
-        # Contratos firmes
-        model.pf_declarada = Param(model.CF, initialize=dict(
-            enumerate(vcf_ed)))  # Energia declarada
-        # Potencia requerida - Si no se flexbiliza deberian de ser igual la energia y la potencia
-        model.pf_req = Param(model.CF, initialize=dict(enumerate(vcf_pr)))
-        # Precio de flexibilidad de contrato
-        # Precio de bloques - Contrato firme - Oferta de flexibilidad
-        model.ffi = Param(model.CF, model.s, initialize=arr2dict(vcf_p))
-        # Magnitud de la oferta - tiene que ser igual a la suma de la energia declarada
-        model.pfi_ofertado = Param(
-            model.CF, model.s, initialize=arr2dict(vcf_m))
-        model.bin_cfi = Param(
-            model.i, model.CF, initialize=arr2dict(var_bin_cfi))
-        model.bin_cfr = Param(
-            model.i, model.CF, initialize=arr2dict(var_bin_cfr))
-
-        # Ofertas de flexibilidad de contratos fisicos flexibles
-        # Ofertas de inyeccion
-        model.pff_declarada = Param(
-            model.CFF, initialize=dict(enumerate(vnfff_ed)))
-        model.pffi_ofertado = Param(
-            model.CFF, model.s, initialize=arr2dict(vnfff_m_i))  # Magnitud del bloque
-        model.fffi = Param(model.CFF, model.s, initialize=arr2dict(
-            p_cnfffi))  # Precio de inyeccion
-        model.bin_pffi = Param(
-            model.i, model.CFF, initialize=arr2dict(var_bin_cnfffi))
-
-        # Oferta de retiro
-        model.pffr_ofertado = Param(model.CFF, model.s, initialize=arr2dict(
-            vnfff_m_r))  # Magnitud de bloque de retiro ofertado
-        # Precio de bloques - Contrato no firme fisico flexible
-        model.fffr = Param(model.CFF, model.s, initialize=arr2dict(p_cnfffr))
-        model.bin_pffr = Param(
-            model.i, model.CFF, initialize=arr2dict(var_bin_cnfffr))
-
-        # Ofertad de pago maximo por CVT
-        model.k = Param(model.CFF, initialize=dict(
-            enumerate(k_cnfffcvt)))  # Indicador de oferta
-        model.pfft_ofertado = Param(model.CFF, model.s, initialize=arr2dict(
-            vnfff_m_cvt))  # Magnitud del bloque
-        model.ffft = Param(model.CFF, model.s, initialize=arr2dict(
-            p_cnfffcvt))  # Precio de pago maximo CVT
-
-        # Variabeles
-        # Variable ofertas de oportunidad
-        # Parte aceptada de cada bloques de las ofertas de oportunidad de retiro
-        model.pr = Var(model.OR, model.s, domain=NonNegativeReals)
-        # Parte aceptada de cada bloques de las ofertas de oportunidad de inyeccion
-        model.pi = Var(model.OI, model.s, domain=NonNegativeReals)
-
-        # Variables CF
-        # Parte aceptada de cada bloques de las ofertas de flexibilidad de contratos firmes
-        model.pfi = Var(model.CF, model.s, domain=NonNegativeReals)
-
-        # Variables CNFFF
-        # Parte aceptada de cada bloques de las oferta de flexibilidad de retiro
-        model.pffr = Var(model.CFF, model.s, domain=NonNegativeReals)
-        # Parte aceptada de cada bloques de las ofertas de flexibilidad de inyección de los contratos físicos flexibles
-        model.pffi = Var(model.CFF, model.s, domain=NonNegativeReals)
-        # Parte aceptada de cada bloques de las oferta de pago máximo de CVT de los contratos físicos flexibles
-        model.pfft = Var(model.CFF, model.s, domain=NonNegativeReals)
-        # Componente fisica de energia PERIODOria de inyeecion
-        model.pff_iny_fisico = Var(model.CFF, domain=NonNegativeReals)
-        # Componente fisica de energia PERIODOria de retiro
-        model.pff_ret_fisico = Var(model.CFF, domain=NonNegativeReals)
-
-        # Variables FOENS
-        # Energia firme de lo CF
-        model.pf_cortada = Var(model.CF, domain=NonNegativeReals)
-        model.pf_pre_cortada = Var(model.CF, domain=NonNegativeReals)
-        # Energia firme de los CNFFF
-        model.pff_cortada = Var(model.CFF, domain=NonNegativeReals)
-
-        model.fens = Var()
-
-        # Variable problema de optimizacion
-        # Inyeccion por nodo
-        model.inyeccion = Var(model.i, domain=NonNegativeReals)
-        model.retiro = Var(model.i, domain=NonNegativeReals)  # Retiro por nodo
-        model.ref_angular = Var(model.i)  # Fase del voltaje en el nodo
-        model.rtmw_c = Var(model.c)  # Flujo de potencia actica por linea
-
-        # Máximas Capacidades de Trasferencia
-        # Maxima transferenica(interconexion,sentido,periodo)
-        model.Mct = Param(model.inter, model.sen, model.per,
-                          initialize=mct.mct.to_dict())
-        model.DirF = Param(model.inter, initialize=dirf)
-
-        print("Ecuación de Función Objetivo Max. Periodo: " + str(PERIODO))
-
-        def objfunc(model):
-            return ((sum(model.fr[OR, s]*model.pr[OR, s] for OR in model.OR for s in model.s) -  # ┌ FOO
-                     # └
-                     sum(model.fi[OI, s]*model.pi[OI, s] for OI in model.OI for s in model.s) -
-                     # [ FOF
-                     sum(model.ffi[CF, s]*model.pfi[CF, s] for CF in model.CF for s in model.s) +
-                     # ┌
-                     sum(model.fffr[CFF, s]*model.pffr[CFF, s] for CFF in model.CFF for s in model.s) -
-                     # │ FOFF
-                     sum(model.fffi[CFF, s]*model.pffi[CFF, s] for CFF in model.CFF for s in model.s) +
-                     # └
-                     sum(model.ffft[CFF, s]*model.pfft[CFF, s] for CFF in model.CFF for s in model.s) -
-                     # ┌ FOENS
-                     0*model.fens*sum(model.pf_cortada[CF] for CF in model.CF) -
-                     0*model.fens*0.5*sum(model.pff_cortada[CFF] for CFF in model.CFF)))               # └
-        model.OBJ = Objective(rule=objfunc, sense=maximize)
-
-        print("Restricciones del Modelo de Optimización. Periodo: "+str(PERIODO))
-
-        def fens_restriccion(model):
-            if NOR == 0 & NCF == 0 & NCFF > 0:
-                return model.fens == 3*max(model.fffr[CFF, s] for CFF in model.CFF for s in model.s)
-            elif NOR == 0 & NCF > 0 & NCFF == 0:
-                return model.fens == 3*max(model.ffi[CF, s] for CF in model.CF for s in model.s)
-            elif NOR == 0 & NCF > 0 & NCFF > 0:
-                return model.fens == 3*max(max(model.ffi[CF, s] for CF in model.CF for s in model.s),
-                                           max(model.fffr[CFF, s] for CFF in model.CFF for s in model.s))
-            elif NOR > 0 & NCF == 0 & NCFF == 0:
-                return model.fens == 3*max(model.fr[OR, s] for OR in model.OR for s in model.s)
-            elif NOR > 0 & NCF == 0 & NCFF > 0:
-                return model.fens == 3*max(max(model.fr[OR, s] for OR in model.OR for s in model.s),
-                                           max(model.fffr[CFF, s] for CFF in model.CFF for s in model.s))
-            elif NOR > 0 & NCF > 0 & NCFF == 0:
-                return model.fens == 3*max(max(model.fr[OR, s] for OR in model.OR for s in model.s),
-                                           max(model.ffi[CF, s] for CF in model.CF for s in model.s))
-            elif NOR > 0 & NCF > 0 & NCFF > 0:
-                return model.fens == 3*max(max(model.fr[OR, s] for OR in model.OR for s in model.s),
-                                           max(model.fffr[CFF, s]
-                                               for CFF in model.CFF for s in model.s),
-                                           max(model.ffi[CF, s] for CF in model.CF for s in model.s))
-        model.fens_constraint = Constraint(rule=fens_restriccion)
-
-        # Restrecciones FOO
-        def pi_restriccion(model, OI, s):
-            return ((model.pi[OI, s] <= model.pi_ofertado[OI, s]))
-        model.pi_constraint = Constraint(
-            model.OI, model.s, rule=pi_restriccion)
-
-        def pr_restriccion(model, OR, s):
-            return ((model.pr[OR, s] <= model.pr_ofertado[OR, s]))
-        model.pr_constraint = Constraint(
-            model.OR, model.s, rule=pr_restriccion)
-
-        # Restricciones FOF
-        def pfi_restriccion(model, CF, s):
-            return (model.pfi[CF, s] <= model.pfi_ofertado[CF, s])
-        model.pfi_constraint = Constraint(
-            model.CF, model.s, rule=pfi_restriccion)
-
-        # Restricciones FOFF
-        def pffr_restriccion(model, CFF, s):
-            return (model.pffr[CFF, s] <= model.pffr_ofertado[CFF, s])
-        model.pffr_constraint = Constraint(
-            model.CFF, model.s, rule=pffr_restriccion)
-
-        def pffi_restriccion(model, CFF, s):
-            return (model.pffi[CFF, s] <= model.pffi_ofertado[CFF, s])
-        model.pffi_constraint = Constraint(
-            model.CFF, model.s, rule=pffi_restriccion)
-
-        if (model.k[CFF] == 0 for CFF in model.CFF):
-            def pfft_restriccion(model, CFF, s):
-                # if  model.k[CFF] ==0:
-                return (model.pfft[CFF, s] <= model.pfft_ofertado[CFF, s])
-            model.pfft_constraint = Constraint(
-                model.CFF, model.s, rule=pfft_restriccion)
-
-        # K(cff) vale 0 si hay oferta de pago maximo por CVT
-        def pff_iny_fisico_restriccion(model, CFF):
-            if model.k[CFF] == 0:
-                return (model.pff_iny_fisico[CFF] == sum(model.pfft[CFF, s] for s in model.s) - sum(model.pffr[CFF, s] for s in model.s))
-            elif model.k[CFF] == 1:
-                return (model.pff_iny_fisico[CFF] == model.pff_declarada[CFF] - sum(model.pffr[CFF, s] for s in model.s))
-        model.pff_iny_fisico_constraint = Constraint(
-            model.CFF, rule=pff_iny_fisico_restriccion)
-
-        def pff_ret_fisico_restriccion(model, CFF):
-            if model.k[CFF] == 0:
-                return (model.pff_ret_fisico[CFF] == sum(model.pfft[CFF, s] for s in model.s) - sum(model.pffi[CFF, s] for s in model.s))
-            elif model.k[CFF] == 1:
-                return (model.pff_ret_fisico[CFF] == model.pff_declarada[CFF] - model.pff_cortada[CFF] - sum(model.pffi[CFF, s] for s in model.s))
-        model.pff_ret_fisico_constraint = Constraint(
-            model.CFF, rule=pff_ret_fisico_restriccion)
-
-        # Restriccion FOENS
-        def pff_cortada_restriccion(model, CFF):
-            return (model.pff_cortada[CFF] <= model.pff_declarada[CFF])
-        model.pff_cortada_constraint = Constraint(
-            model.CFF, rule=pff_cortada_restriccion)
-
-        def pf_cortada_restriccion(model, CF):
-            return (model.pf_cortada[CF] <= model.pf_req[CF])
-        model.pf_cortada_constraint = Constraint(
-            model.CF, rule=pf_cortada_restriccion)
-
-        print('Restricciones de transmision. Periodo: ' + str(PERIODO))
-        # Restricciones de transmision
-
-        def inyec(model, i):
-            return (model.inyeccion[i] == model.G[i] +
-                    sum(model.pi[OI, s]*model.bin_pi[i, OI] for OI in model.OI for s in model.s) +
-                    sum(model.pfi[CF, s]*model.bin_cfi[i, CF] for CF in model.CF for s in model.s) +
-                    sum(model.pff_iny_fisico[CFF]*model.bin_pffi[i, CFF] for CFF in model.CFF))
-        model.inyec_constraint = Constraint(model.i, rule=inyec)
-
-        def retiro(model, i):
-            return (model.retiro[i] == model.D[i] +
-                    sum(model.pr[OR, s]*model.bin_pr[i, OR] for OR in model.OR for s in model.s) +
-                    sum(model.pf_req[CF]*model.bin_cfr[i, CF] for CF in model.CF) +
-                    sum(model.pff_ret_fisico[CFF]*model.bin_pffr[i, CFF] for CFF in model.CFF) -
-                    0*sum(model.pf_cortada[CF]*model.bin_cfr[i, CF] for CF in model.CF) -
-                    0*sum(model.pf_pre_cortada[CF]*model.bin_cfr[i, CF] for CF in model.CF))
-        model.retiro_constraint = Constraint(model.i, rule=retiro)
-
-        # Los multiplicadore o variable duales de esta restriccion son los precios nodales
-        def balance_inyeccion_retiro(model, i):
-            return (model.inyeccion[i] + sum(model.Inc[c, i]*model.rtmw_c[c] for c in model.c) -  # Al dividir entre 100 Rc
-                    # toda la ec. se pasa a p.u.
-                    0.5*sum(((model.Inc[c, i]*model.rtmw_c[c])**2)
-                            * (model.Rc[c]/100) for c in model.c)
-                    == model.retiro[i])
-        model.balance_inyeccion_retiro_constraint = Constraint(
-            model.i, rule=balance_inyeccion_retiro)
-
-        def rtmw_min_restriccion(model, c):
-            return (model.rtmw_c[c] >= -model.rtmw_min[c])
-        model.rtmw_min_constraint = Constraint(
-            model.c, rule=rtmw_min_restriccion)
-
-        def rtmw_max_restriccion(model, c):
-            return (model.rtmw_c[c] <= model.rtmw_max[c])
-        model.rtmw_max_constraint = Constraint(
-            model.c, rule=rtmw_max_restriccion)
-
-        def flujo_potencia_actica(model, c):
-            return ((model.Xc[c])*model.rtmw_c[c]+sum(model.Inc[c, i]*model.ref_angular[i] for i in model.i) == 0)
-        model.flujo_potencia_actica_constraint = Constraint(
-            model.c, rule=flujo_potencia_actica)
-
-        # Máximas capacidades de trasferencia entre áreas de control
-        def eq_mct_ns_rule(model, inter):
-            if inter == 'ES':  # Maxima exportacion de El Salvador
-                return (-(model.DirF[inter]*model.rtmw_c[lin_mct[inter][0]]+model.DirF[inter]*model.rtmw_c[lin_mct[inter][1]]) +
-                        (model.DirF[inter]*model.rtmw_c[lin_mct[inter][2]]+model.DirF[inter]*model.rtmw_c[lin_mct[inter][3]])) <= model.Mct[inter, 'ns', PERIODO] + 0.001
-            elif inter == 'HON':  # Maxima importacion de Honduras
-                return (-(model.DirF[inter]*model.rtmw_c[lin_mct[inter][0]]+model.DirF[inter]*model.rtmw_c[lin_mct[inter][1]] +
-                          model.DirF[inter]*model.rtmw_c[lin_mct[inter][2]]) + (model.DirF[inter]*model.rtmw_c[lin_mct[inter][3]] +
-                                                                                model.DirF[inter]*model.rtmw_c[lin_mct[inter][4]])) <= model.Mct[inter, 'sn', PERIODO] + 0.001
-            else:
-                return sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct[inter]) <= model.Mct[inter, 'ns', PERIODO] + 0.001
-        model.eq_mct_ns = Constraint(model.inter, rule=eq_mct_ns_rule)
-
-        def eq_mct_sn_rule(model, inter):
-            if inter == 'ES':  # Maxima importacion de El Salvador
-                return (-(model.DirF[inter]*model.rtmw_c[lin_mct[inter][0]]+model.DirF[inter]*model.rtmw_c[lin_mct[inter][1]]) +
-                        (model.DirF[inter]*model.rtmw_c[lin_mct[inter][2]]+model.DirF[inter]*model.rtmw_c[lin_mct[inter][3]])) >= -model.Mct[inter, 'sn', PERIODO] + 0.00001
-            elif inter == 'HON':  # Maxima importacion de Honduras
-                return (-(model.DirF[inter]*model.rtmw_c[lin_mct[inter][0]]+model.DirF[inter]*model.rtmw_c[lin_mct[inter][1]] +
-                          model.DirF[inter]*model.rtmw_c[lin_mct[inter][2]]) + (model.DirF[inter]*model.rtmw_c[lin_mct[inter][3]] +
-                                                                                model.DirF[inter]*model.rtmw_c[lin_mct[inter][4]])) >= -model.Mct[inter, 'ns', PERIODO] + 0.00001
-            else:
-                return sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct[inter]) >= -model.Mct[inter, 'sn', PERIODO] + 0.00001
-        model.eq_mct_sn = Constraint(model.inter, rule=eq_mct_sn_rule)
-
-        model.dual = Suffix(direction=Suffix.IMPORT)
-
-        print("Construcción del modelo terminada. Periodo: "+str(PERIODO))
-
-        opt = SolverFactory('ipopt')
-        #opt.options['max_iter']= 10000
-        result = opt.solve(model)
-        model.solutions.store_to(result)
-
-        # Cálculo de Precios Nodales
-        # =============================================================================
-        print("Calculando Precios Nodales. Periodo:" + str(PERIODO))
-        Sigma = zeros(nb)
-        for i in model.i:
-            Sigma[i] = model.dual[model.balance_inyeccion_retiro_constraint[i]]
-
-        # Construcción de array para grabar
-        # =============================================================================
-        flujos = DataFrame()
-        flujos['Periodo'] = set_periodo(nbr, PERIODO)
-        flujos['BUS I'] = brnames['BUS I']
-        flujos['BUS J'] = brnames['BUS J']
-        flujos['CKT'] = brnames['CKT']
-        f = array(list(model.rtmw_c.get_values().values()))
-        perdidas = zeros(nbr)
-        for c in model.c:
-            perdidas[c] = (f[c]**2)*rc[c]/100
-        flujos['Flujo'] = f
-        flujos['Perdidas'] = perdidas
-        # Guarda los resultados con los anteriores
-        flujos_t = concat([flujos_t, flujos])
-
-        pon = DataFrame()
-        result_inyeccion = array(list(model.inyeccion.get_values().values()))
-        result_retiro = array(list(model.retiro.get_values().values()))
-        pon['Periodo'] = set_periodo(nb, PERIODO)
-        pon['nodo'] = bus
-        pon['Precio Exante'] = Sigma*-1
-        # Guarda los resultados con los anteriores
-        pon_t = concat([pon_t, pon])
-        # print(pon)
-
-        iep = DataFrame()
-        iep['Periodo'] = set_periodo(nb, PERIODO)
-        iep['nodo'] = bus
-        iep['Inyeccion'] = result_inyeccion
-        iep['Retiro'] = result_retiro
-        # Guarda los resultados con los anteriores
-        iep_t = concat([iep_t, iep])
-
-        result_pff_iny = array(
-            list(model.pff_iny_fisico.get_values().values()))
-        result_pff_ret = array(
-            list(model.pff_ret_fisico.get_values().values()))
-        result_pr = setvariable_p(
-            array(list(model.pr.get_values().values())), NOR)
-        result_pi = setvariable_p(
-            array(list(model.pi.get_values().values())), NOI)
-        result_pfi = setvariable_p(
-            array(list(model.pfi.get_values().values())), NCF)
-        result_pffr = setvariable_p(
-            array(list(model.pffr.get_values().values())), NCFF)
-        result_pffi = setvariable_p(
-            array(list(model.pffi.get_values().values())), NCFF)
-        result_pfft = setvariable_p(
-            array(list(model.pfft.get_values().values())), NCFF)
-
-        result_foo_r = DataFrame()
-        result_foo_r['Periodo'] = ex_oor['periodo']
-        result_foo_r['N°'] = ex_oor['N°']
-        result_foo_r['Pr Bloque 1'] = result_pr[:, 0]
-        result_foo_r['Pr Bloque 2'] = result_pr[:, 1]
-        result_foo_r['Pr Bloque 3'] = result_pr[:, 2]
-        result_foo_r['Pr Bloque 4'] = result_pr[:, 3]
-        result_foo_r['Pr Bloque 5'] = result_pr[:, 4]
-        # Guarda los resultados con los anteriores
-        result_foo_r_t = concat([result_foo_r_t, result_foo_r])
-
-        result_foo_i = DataFrame()
-        result_foo_i['Periodo'] = ex_ooi['periodo']
-        result_foo_i['N°'] = ex_ooi['N°']
-        result_foo_i['Pi Bloque 1'] = result_pi[:, 0]
-        result_foo_i['Pi Bloque 2'] = result_pi[:, 1]
-        result_foo_i['Pi Bloque 3'] = result_pi[:, 2]
-        result_foo_i['Pi Bloque 4'] = result_pi[:, 3]
-        result_foo_i['Pi Bloque 5'] = result_pi[:, 4]
-        # Guarda los resultados con los anteriores
-        result_foo_i_t = concat([result_foo_i_t, result_foo_i])
-
-        result_fof = DataFrame()
-        result_fof['Periodo'] = ex_cf['periodo']
-        result_fof['N°'] = ex_cf['N°']
-        result_fof['Pfi Bloque 1'] = result_pfi[:, 0]
-        result_fof['Pfi Bloque 2'] = result_pfi[:, 1]
-        result_fof['Pfi Bloque 3'] = result_pfi[:, 2]
-        result_fof['Pfi Bloque 4'] = result_pfi[:, 3]
-        result_fof['Pfi Bloque 5'] = result_pfi[:, 4]
-        # Guarda los resultados con los anteriores
-        result_fof_t = concat([result_fof_t, result_fof])
-
-        result_foff = DataFrame()
-        result_foff['Periodo'] = ex_cnfff['periodo']
-        result_foff['N°'] = ex_cnfff['N°']
-        result_foff['Pffr Bloque 1'] = result_pffr[:, 0]
-        result_foff['Pffr Bloque 2'] = result_pffr[:, 1]
-        result_foff['Pffr Bloque 3'] = result_pffr[:, 2]
-        result_foff['Pffr Bloque 4'] = result_pffr[:, 3]
-        result_foff['Pffr Bloque 5'] = result_pffr[:, 4]
-        result_foff['Pffi Bloque 1'] = result_pffi[:, 0]
-        result_foff['Pffi Bloque 2'] = result_pffi[:, 1]
-        result_foff['Pffi Bloque 3'] = result_pffi[:, 2]
-        result_foff['Pffi Bloque 4'] = result_pffi[:, 3]
-        result_foff['Pffi Bloque 5'] = result_pffi[:, 4]
-        result_foff['Pfft Bloque 1'] = result_pfft[:, 0]
-        result_foff['Pfft Bloque 2'] = result_pfft[:, 1]
-        result_foff['Pfft Bloque 3'] = result_pfft[:, 2]
-        result_foff['Pfft Bloque 4'] = result_pfft[:, 3]
-        result_foff['Pfft Bloque 5'] = result_pfft[:, 4]
-        # Guarda los resultados con los anteriores
-        result_foff_t = concat([result_foff_t, result_foff])
-
-        foo_ret_iny = DataFrame()
-        foo_ret_iny['Periodo'] = ex_cnfff['periodo']
-        foo_ret_iny['N°'] = ex_cnfff['N°']
-        foo_ret_iny['Inyeccion'] = result_pff_iny
-        foo_ret_iny['Retiro'] = result_pff_ret
-        # Guarda los resultados con los anteriores
-        foo_ret_iny_t = concat([foo_ret_iny_t, foo_ret_iny])
-
-    print("Escribiendo resultados en carpeta.")
-    filename = path.basename(file).split('.')
-    filepath = path.dirname(file)
-    new_filename = filename[0]+'_results.'+filename[1]
-    new_file = path.join(filepath, new_filename)
-    writer = ExcelWriter(new_file)
-    flujos_t.to_excel(writer, 'IEP-RTR', index=False)
-    iep_t.to_excel(writer, 'IEP-TOTAL', index=False)
-    pon_t.to_excel(writer, 'PEXANTES', index=False)
-    result_foo_i_t.to_excel(writer, 'TOP-I', index=False)
-    result_foo_r_t.to_excel(writer, 'TOP-R', index=False)
-    result_fof_t.to_excel(writer, 'TCP-CF', index=False)
-    result_foff_t.to_excel(writer, 'TCP-CNFFF-1', index=False)
-    foo_ret_iny_t.to_excel(writer, 'TCP-CNFFF-2', index=False)
-    writer.save()
-
-    print("{:=^100}".format(""))
-    print("{:^100}".format(" Script Finalizado "))
-    print("{:^100}".format(" Mercados Eléctricos de Centroamérica (c) 2020 "))
-    print("{:=^100}".format(""))
-
-    return 0
+def main():
+    sys.stdout = log.NullStream()
+    log.logger.info('El Sistema ha iniciado ha iniciado')
+    root = tk.Tk()
+    app = App(root)
+    app.root.lift()
+    app.root.attributes('-topmost', True)
+    app.root.attributes('-topmost', False)
+    app.root.mainloop()
 
 
 if __name__ == "__main__":
-    setmodel()  # faltan argumentos
+    main()

+ 0 - 0
Predespacho_24horas/Manual Modelo_Predespacho_24h.docx → manuales/Manual Modelo_Predespacho_24h.docx


+ 0 - 0
Predespacho_24horas/Manual Modelo_Predespacho_24h.pdf → manuales/Manual Modelo_Predespacho_24h.pdf


+ 0 - 0
Predespacho_24horas/__pycache__/predespacho_24h.cpython-37.pyc → manuales/__pycache__/predespacho_24h.cpython-37.pyc


+ 0 - 0
Predespacho_24horas/~$nual Modelo_Predespacho_24h.docx → manuales/~$nual Modelo_Predespacho_24h.docx


二進制
mc3.exe


二進制
mct/__pycache__/__init__.cpython-38.pyc


二進制
mct/__pycache__/makeMCT.cpython-38.pyc


+ 685 - 0
presdespacho.py

@@ -0,0 +1,685 @@
+
+from __future__ import division
+
+import logging
+import traceback
+from os import path
+import sys
+
+import pyutilib.subprocess.GlobalData
+from numpy import array, zeros
+from pandas import DataFrame, ExcelWriter
+from pyomo.environ import *
+from pyomo.environ import SolverFactory
+from pyomo.kernel import value
+
+from common.data import APPDIRS
+
+from mct.makeMCT import linmct, readmct, set_dir_flujo
+from red.create import *
+from red.create1 import *
+from red.makeBdc import makeBdc
+from red.read import excel2net
+from utils.arr2dict import arr2dict
+
+pyutilib.subprocess.GlobalData.DEFINE_SIGNAL_HANDLERS_DEFAULT = False
+
+logger = logging.getLogger('spr.run.modelo')
+
+
+def setmodel(file, p_exec, all_day=True):
+
+    # Determinar si se ejecuta todo el día o solo un período en específico
+    if all_day:
+        min = 0
+        max = p_exec + 1
+
+        logger.info("Se ejecuta el Modelo de Predespacho para las 24 horas")
+
+    else:
+        min = p_exec
+        max = p_exec + 1
+
+        logger.info(
+            "Se ejecuta el Modelo de Predespacho para la hora {}".format(p_exec))
+
+    logger.info("Modelo de Predespacho Regional")
+    logger.info("Mercados Eléctricos de Centroamérica (c) 2020")
+
+    # ============================================================================
+    # Importación de datos desde archivo Excel
+    # ============================================================================
+
+    # Parametros de la linea
+    logger.info("Inicio Predespacho Regional")
+    logger.info("Leyendo información de RTR...")
+    net = excel2net(file)
+    bus = setbus(net)  # Nodos
+    branch = setbranch(net, bus)  # Set lineas
+    bu = branch[:, 5]  # potenica max de la linea
+    bl = branch[:, 6]  # potenica min de la linea
+    xc = branch[:, 3]  # Reactancia de la linea
+    rc = branch[:, 4]  # Resistencia de la linea
+    nb = bus.shape[0]  # Numero de nodos
+    nbr = branch.shape[0]  # Numero de lineas
+    A = makeBdc(bus, branch)  # Matriz incidente
+    brnames = branchnames(bus, branch)  # Nombre de las lineas
+    inc = A.toarray()*-1
+
+    # Lineas para límites de MCT
+    br_t = brnames['Total'].to_numpy()
+    lin_mct = linmct(br_t)
+    dirf = set_dir_flujo()
+    mct = readmct(file)
+
+    # Informacion de los despachos nacionales
+    dg_t = read_D_G(file)
+
+    # Ofertas de todos los periodos
+    ex_cnfff_t = readofertas_cnfffs(file)
+    ex_ooi_t = readofertas_oois(file)
+    ex_oor_t = readofertas_oors(file)
+    ex_cf_t = readofertas_cfs(file)
+
+    # Dataframe para almacenar la informacion de cada predespacho
+    flujos_t = DataFrame()
+    iep_t = DataFrame()
+    pon_t = DataFrame()
+    result_foo_i_t = DataFrame()
+    result_foo_r_t = DataFrame()
+    result_fof_t = DataFrame()
+    result_foff_t = DataFrame()
+    foo_ret_iny_t = DataFrame()
+
+    # El range del for se modifica dependiendo los periodos que se quieren correr.
+    for PERIODO in range(min, max):
+        logger.info("Inicio de la ejecución para el periodo {}".format(PERIODO))
+
+        logger.info("Leyendo información de los despacho nacionales.")
+        # Dependiendo de los valores de la columna periodo del df son los valores que toma
+        dg = dg_t[dg_t.periodo.isin([PERIODO])]
+        # Resetea valores de ordenamiento del DF
+        dg.reset_index(drop=True, inplace=True)
+        # Ordena los valores que tiene segun los nodos de rtr
+        dg_n = set_dgnacional(bus, dg)
+
+        logger.info("Leyendo información de ofertas.")
+        # Funcion leer contratos no firmes fisicos flexibles
+        # Dependiendo de los valores de la columna periodo del df son los valores que toma
+        ex_cnfff = ex_cnfff_t[ex_cnfff_t.periodo.isin([PERIODO])]
+        # Resetea valores de ordenamiento del DF
+        ex_cnfff.reset_index(drop=True, inplace=True)
+        # Energia declarada con respecto al nodo
+        vnfff_ed = setvariable(ex_cnfff['energía_dec'])
+        # Magnitud de energia ofertada -flexibilizacion
+        vnfff_m_i = setvariable_s(
+            ex_cnfff[['magnitud_i1', 'magnitud_i2', 'magnitud_i3', 'magnitud_i4', 'magnitud_i5']])
+        vnfff_m_r = setvariable_s(
+            ex_cnfff[['magnitud_r1', 'magnitud_r2', 'magnitud_r3', 'magnitud_r4', 'magnitud_r5']])
+        vnfff_m_cvt = setvariable_s(
+            ex_cnfff[['magnitud_cvt1', 'magnitud_cvt2', 'magnitud_cvt3', 'magnitud_cvt4', 'magnitud_cvt5']])
+        # Precio de la ofertas de inyeccion
+        p_cnfffi = setvariable_s(
+            ex_cnfff[['precio_i1', 'precio_i2', 'precio_i3', 'precio_i4', 'precio_i5']])
+        # Precio de la ofertas de retiro
+        p_cnfffr = setvariable_s(
+            ex_cnfff[['precio_r1', 'precio_r2', 'precio_r3', 'precio_r4', 'precio_r5']])
+        # Precio de la ofertas de inyeccion
+        p_cnfffcvt = setvariable_s(
+            ex_cnfff[['precio_cvt1', 'precio_cvt2', 'precio_cvt3', 'precio_cvt4', 'precio_cvt5']])
+        # Precio de la ofertas de inyeccion
+        k_cnfffcvt = setvariable(ex_cnfff['k'])
+        NCFF = ex_cnfff.shape[0]  # Numero de contratos firmes
+        var_bin_cnfffr = MATRIZ_VNFFF_R(bus, ex_cnfff)
+        var_bin_cnfffi = MATRIZ_VNFFF_I(bus, ex_cnfff)
+        dem = setvariable(dg_n['Demanda'])
+        gen = setvariable(dg_n['Generacion'])
+
+        # Funcion leer parametros oferta de oportunidad inyeccion
+        # Dependiendo de los valores de la columna periodo del df son los valores que toma
+        ex_ooi = ex_ooi_t[ex_ooi_t.periodo.isin([PERIODO])]
+        # Resetea valores de ordenamiento del DF
+        ex_ooi.reset_index(drop=True, inplace=True)
+        vooi_m = setvariable_s(ex_ooi[['magnitud_ooi1', 'magnitud_ooi2', 'magnitud_ooi3',
+                                       'magnitud_ooi4', 'magnitud_ooi5']])  # Ofertas con respecto al nodo
+        p_ooi = setvariable_s(ex_ooi[['precio_ooi1', 'precio_ooi2', 'precio_ooi3',
+                                      'precio_ooi4', 'precio_ooi5']])  # Precio de la ofertas
+        NOI = ex_ooi.shape[0]  # Numero de ofertas de inyeccion
+        var_bin_ooi = MATRIZ_OOI(bus, ex_ooi)
+
+        # Funcion leer parametros oferta de oportunidad retiro
+        ex_oor = ex_oor_t[ex_oor_t.periodo.isin([PERIODO])]
+        # Resetea valores de ordenamiento del DF
+        ex_oor.reset_index(drop=True, inplace=True)
+        voor_m = setvariable_s(ex_oor[['magnitud_oor1', 'magnitud_oor2', 'magnitud_oor3',
+                                       'magnitud_oor4', 'magnitud_oor5']])  # Ofertas con respecto al nodo
+        # Precio de la ofertas - flexibilizacion
+        p_oor = setvariable_s(
+            ex_oor[['precio_oor1', 'precio_oor2', 'precio_oor3', 'precio_oor4', 'precio_oor5']])
+        NOR = ex_oor.shape[0]  # Numero de ofertas de retiro
+        var_bin_oor = MATRIZ_OOR(bus, ex_oor)
+
+        # Funcion leer parametros contratos firmes
+        # Dependiendo de los valores de la columna periodo del df son los valores que toma
+        ex_cf = ex_cf_t[ex_cf_t.periodo.isin([PERIODO])]
+        # Resetea valores de ordenamiento del DF
+        ex_cf.reset_index(drop=True, inplace=True)
+        # Energia declarada con respecto al nodo
+        vcf_ed = setvariable(ex_cf['energía_dec'])
+        # Potencia requerida con respecto al nodo
+        vcf_pr = setvariable(ex_cf['potencia_req'])
+        # Magnitud de energia ofertada -flexibilizacion
+        vcf_m = setvariable_s(
+            ex_cf[['magnitu_cf1', 'magnitu_cf2', 'magnitu_cf3', 'magnitu_cf4', 'magnitu_cf5']])
+        # Precio de la ofertas
+        vcf_p = setvariable_s(
+            ex_cf[['precio_cf1', 'precio_cf2', 'precio_cf3', 'precio_cf4', 'precio_cf5']])
+        NCF = ex_cf.shape[0]  # Numero de contratos firmes
+        var_bin_cfr = MATRIZ_CFR(bus, ex_cf)
+        var_bin_cfi = MATRIZ_CFI(bus, ex_cf)
+
+        # Inicio del modelo de optimización
+        model = ConcreteModel()
+
+        # sets
+        model.i = Set(initialize=range(0, nb))  # numero de nodos
+        model.c = Set(initialize=range(0, nbr))  # Numero de lineas
+        # numero de ofertas de oportuniddad retiro
+        model.OR = Set(initialize=range(0, NOR))
+        # numero de ofertas de oportunidad inyeccion
+        model.OI = Set(initialize=range(0, NOI))
+        # numero de ofertas de CNFFF
+        model.CFF = Set(initialize=range(0, NCFF))
+        # numero de ofertas de contratos firmes
+        model.CF = Set(initialize=range(0, NCF))
+        model.s = Set(initialize=range(0, 5))  # Numero de bloques
+        model.inter = Set(initialize=lin_mct.keys())  # Interconexiones
+        # Sentidos de interconexiones
+        model.sen = Set(initialize=['sn', 'ns'])
+        model.per = Set(initialize=range(0, 24))  # numero de periodos
+
+        # Parametros
+        # Parametros de la red
+        model.rtmw_min = Param(model.c, initialize=dict(enumerate(bl)))
+        model.rtmw_max = Param(model.c, initialize=dict(enumerate(bu)))
+        model.Inc = Param(model.c, model.i, initialize=arr2dict(inc))
+        model.Xc = Param(model.c, initialize=dict(enumerate(xc)))
+        model.Rc = Param(model.c, initialize=dict(enumerate(rc)))
+
+        # Parametros de los predespachos nacionales
+        model.D = Param(model.i, initialize=dict(enumerate(dem)))
+        model.G = Param(model.i, initialize=dict(enumerate(gen)))
+
+        # Ofertas de oportunidad
+        # Oferta de oportunidad de retiro
+        # Oferta bloques 1
+        model.fr = Param(model.OR, model.s, initialize=arr2dict(p_oor))
+        model.pr_ofertado = Param(model.OR, model.s, initialize=arr2dict(
+            voor_m))  # Magnitud de la oferta MW-h
+        model.bin_pr = Param(
+            model.i, model.OR, initialize=arr2dict(var_bin_oor))
+
+        # Oferta de oportunidad de inyeccion
+        # Precio de bloques - Oferta de oportunidad de inyeccion
+        model.fi = Param(model.OI, model.s, initialize=arr2dict(p_ooi))
+        model.pi_ofertado = Param(model.OI, model.s, initialize=arr2dict(
+            vooi_m))  # Magnitud de la oferta MW-h
+        model.bin_pi = Param(
+            model.i, model.OI, initialize=arr2dict(var_bin_ooi))
+
+        # Contratos firmes
+        model.pf_declarada = Param(model.CF, initialize=dict(
+            enumerate(vcf_ed)))  # Energia declarada
+        # Potencia requerida - Si no se flexbiliza deberian de ser igual la energia y la potencia
+        model.pf_req = Param(model.CF, initialize=dict(enumerate(vcf_pr)))
+        # Precio de flexibilidad de contrato
+        # Precio de bloques - Contrato firme - Oferta de flexibilidad
+        model.ffi = Param(model.CF, model.s, initialize=arr2dict(vcf_p))
+        # Magnitud de la oferta - tiene que ser igual a la suma de la energia declarada
+        model.pfi_ofertado = Param(
+            model.CF, model.s, initialize=arr2dict(vcf_m))
+        model.bin_cfi = Param(
+            model.i, model.CF, initialize=arr2dict(var_bin_cfi))
+        model.bin_cfr = Param(
+            model.i, model.CF, initialize=arr2dict(var_bin_cfr))
+
+        # Ofertas de flexibilidad de contratos fisicos flexibles
+        # Ofertas de inyeccion
+        model.pff_declarada = Param(
+            model.CFF, initialize=dict(enumerate(vnfff_ed)))
+        model.pffi_ofertado = Param(
+            model.CFF, model.s, initialize=arr2dict(vnfff_m_i))  # Magnitud del bloque
+        model.fffi = Param(model.CFF, model.s, initialize=arr2dict(
+            p_cnfffi))  # Precio de inyeccion
+        model.bin_pffi = Param(
+            model.i, model.CFF, initialize=arr2dict(var_bin_cnfffi))
+
+        # Oferta de retiro
+        model.pffr_ofertado = Param(model.CFF, model.s, initialize=arr2dict(
+            vnfff_m_r))  # Magnitud de bloque de retiro ofertado
+        # Precio de bloques - Contrato no firme fisico flexible
+        model.fffr = Param(model.CFF, model.s, initialize=arr2dict(p_cnfffr))
+        model.bin_pffr = Param(
+            model.i, model.CFF, initialize=arr2dict(var_bin_cnfffr))
+
+        # Ofertad de pago maximo por CVT
+        model.k = Param(model.CFF, initialize=dict(
+            enumerate(k_cnfffcvt)))  # Indicador de oferta
+        model.pfft_ofertado = Param(model.CFF, model.s, initialize=arr2dict(
+            vnfff_m_cvt))  # Magnitud del bloque
+        model.ffft = Param(model.CFF, model.s, initialize=arr2dict(
+            p_cnfffcvt))  # Precio de pago maximo CVT
+
+        # Variabeles
+        # Variable ofertas de oportunidad
+        # Parte aceptada de cada bloques de las ofertas de oportunidad de retiro
+        model.pr = Var(model.OR, model.s, domain=NonNegativeReals)
+        # Parte aceptada de cada bloques de las ofertas de oportunidad de inyeccion
+        model.pi = Var(model.OI, model.s, domain=NonNegativeReals)
+
+        # Variables CF
+        # Parte aceptada de cada bloques de las ofertas de flexibilidad de contratos firmes
+        model.pfi = Var(model.CF, model.s, domain=NonNegativeReals)
+
+        # Variables CNFFF
+        # Parte aceptada de cada bloques de las oferta de flexibilidad de retiro
+        model.pffr = Var(model.CFF, model.s, domain=NonNegativeReals)
+        # Parte aceptada de cada bloques de las ofertas de flexibilidad de inyección de los contratos físicos flexibles
+        model.pffi = Var(model.CFF, model.s, domain=NonNegativeReals)
+        # Parte aceptada de cada bloques de las oferta de pago máximo de CVT de los contratos físicos flexibles
+        model.pfft = Var(model.CFF, model.s, domain=NonNegativeReals)
+        # Componente fisica de energia PERIODOria de inyeecion
+        model.pff_iny_fisico = Var(model.CFF, domain=NonNegativeReals)
+        # Componente fisica de energia PERIODOria de retiro
+        model.pff_ret_fisico = Var(model.CFF, domain=NonNegativeReals)
+
+        # Variables FOENS
+        # Energia firme de lo CF
+        model.pf_cortada = Var(model.CF, domain=NonNegativeReals)
+        model.pf_pre_cortada = Var(model.CF, domain=NonNegativeReals)
+        # Energia firme de los CNFFF
+        model.pff_cortada = Var(model.CFF, domain=NonNegativeReals)
+
+        model.fens = Var()
+
+        # Variable problema de optimizacion
+        # Inyeccion por nodo
+        model.inyeccion = Var(model.i, domain=NonNegativeReals)
+        model.retiro = Var(model.i, domain=NonNegativeReals)  # Retiro por nodo
+        model.ref_angular = Var(model.i)  # Fase del voltaje en el nodo
+        model.rtmw_c = Var(model.c)  # Flujo de potencia actica por linea
+
+        # Máximas Capacidades de Trasferencia
+        # Maxima transferenica(interconexion,sentido,periodo)
+        model.Mct = Param(model.inter, model.sen, model.per,
+                          initialize=mct.mct.to_dict())
+        model.DirF = Param(model.inter, initialize=dirf)
+
+        logger.info("Ecuación de Función Objetivo Max.")
+
+        def objfunc(model):
+            return ((sum(model.fr[OR, s]*model.pr[OR, s] for OR in model.OR for s in model.s) -  # ┌ FOO
+                     # └
+                     sum(model.fi[OI, s]*model.pi[OI, s] for OI in model.OI for s in model.s) -
+                     # [ FOF
+                     sum(model.ffi[CF, s]*model.pfi[CF, s] for CF in model.CF for s in model.s) +
+                     # ┌
+                     sum(model.fffr[CFF, s]*model.pffr[CFF, s] for CFF in model.CFF for s in model.s) -
+                     # │ FOFF
+                     sum(model.fffi[CFF, s]*model.pffi[CFF, s] for CFF in model.CFF for s in model.s) +
+                     # └
+                     sum(model.ffft[CFF, s]*model.pfft[CFF, s]
+                         for CFF in model.CFF for s in model.s)))  # -
+            # ┌ FOENS
+            #  0*model.fens*sum(model.pf_cortada[CF] for CF in model.CF) -
+            #  0*model.fens*0.5*sum(model.pff_cortada[CFF] for CFF in model.CFF)))               # └
+        model.OBJ = Objective(rule=objfunc, sense=maximize)
+
+        logger.info("Restricciones del Modelo de Optimización. ")
+
+        # Esta restricción no es utilizada y se encarga de efectuar la reducción
+        # de los contratos firmes (idem FOENS línea 327)
+
+        # def fens_restriccion(model):
+        #     if NOR == 0 & NCF == 0 & NCFF > 0:
+        #         return model.fens == 3*max(model.fffr[CFF, s] for CFF in model.CFF for s in model.s)
+        #     elif NOR == 0 & NCF > 0 & NCFF == 0:
+        #         return model.fens == 3*max(model.ffi[CF, s] for CF in model.CF for s in model.s)
+        #     elif NOR == 0 & NCF > 0 & NCFF > 0:
+        #         return model.fens == 3*max(max(model.ffi[CF, s] for CF in model.CF for s in model.s),
+        #                                    max(model.fffr[CFF, s] for CFF in model.CFF for s in model.s))
+        #     elif NOR > 0 & NCF == 0 & NCFF == 0:
+        #         return model.fens == 3*max(model.fr[OR, s] for OR in model.OR for s in model.s)
+        #     elif NOR > 0 & NCF == 0 & NCFF > 0:
+        #         return model.fens == 3*max(max(model.fr[OR, s] for OR in model.OR for s in model.s),
+        #                                    max(model.fffr[CFF, s] for CFF in model.CFF for s in model.s))
+        #     elif NOR > 0 & NCF > 0 & NCFF == 0:
+        #         return model.fens == 3*max(max(model.fr[OR, s] for OR in model.OR for s in model.s),
+        #                                    max(model.ffi[CF, s] for CF in model.CF for s in model.s))
+        #     elif NOR > 0 & NCF > 0 & NCFF > 0:
+        #         return model.fens == 3*max(max(model.fr[OR, s] for OR in model.OR for s in model.s),
+        #                                    max(model.fffr[CFF, s]
+        #                                        for CFF in model.CFF for s in model.s),
+        #                                    max(model.ffi[CF, s] for CF in model.CF for s in model.s))
+        # model.fens_constraint = Constraint(rule=fens_restriccion)
+
+        # Restrecciones FOO
+
+        def pi_restriccion(model, OI, s):
+            return ((model.pi[OI, s] <= model.pi_ofertado[OI, s]))
+        model.pi_constraint = Constraint(
+            model.OI, model.s, rule=pi_restriccion)
+
+        def pr_restriccion(model, OR, s):
+            return ((model.pr[OR, s] <= model.pr_ofertado[OR, s]))
+        model.pr_constraint = Constraint(
+            model.OR, model.s, rule=pr_restriccion)
+
+        # Restricciones FOF
+        def pfi_restriccion(model, CF, s):
+            return (model.pfi[CF, s] <= model.pfi_ofertado[CF, s])
+        model.pfi_constraint = Constraint(
+            model.CF, model.s, rule=pfi_restriccion)
+
+        # Restricciones FOFF
+        def pffr_restriccion(model, CFF, s):
+            return (model.pffr[CFF, s] <= model.pffr_ofertado[CFF, s])
+        model.pffr_constraint = Constraint(
+            model.CFF, model.s, rule=pffr_restriccion)
+
+        def pffi_restriccion(model, CFF, s):
+            return (model.pffi[CFF, s] <= model.pffi_ofertado[CFF, s])
+        model.pffi_constraint = Constraint(
+            model.CFF, model.s, rule=pffi_restriccion)
+
+        if (model.k[CFF] == 0 for CFF in model.CFF):
+            def pfft_restriccion(model, CFF, s):
+                # if  model.k[CFF] ==0:
+                return (model.pfft[CFF, s] <= model.pfft_ofertado[CFF, s])
+            model.pfft_constraint = Constraint(
+                model.CFF, model.s, rule=pfft_restriccion)
+
+        # K(cff) vale 0 si hay oferta de pago maximo por CVT
+        def pff_iny_fisico_restriccion(model, CFF):
+            if model.k[CFF] == 0:
+                return (model.pff_iny_fisico[CFF] == sum(model.pfft[CFF, s] for s in model.s) - sum(model.pffr[CFF, s] for s in model.s))
+            elif model.k[CFF] == 1:
+                return (model.pff_iny_fisico[CFF] == model.pff_declarada[CFF] - sum(model.pffr[CFF, s] for s in model.s))
+        model.pff_iny_fisico_constraint = Constraint(
+            model.CFF, rule=pff_iny_fisico_restriccion)
+
+        def pff_ret_fisico_restriccion(model, CFF):
+            if model.k[CFF] == 0:
+                return (model.pff_ret_fisico[CFF] == sum(model.pfft[CFF, s] for s in model.s) - sum(model.pffi[CFF, s] for s in model.s))
+            elif model.k[CFF] == 1:
+                return (model.pff_ret_fisico[CFF] == model.pff_declarada[CFF] - model.pff_cortada[CFF] - sum(model.pffi[CFF, s] for s in model.s))
+        model.pff_ret_fisico_constraint = Constraint(
+            model.CFF, rule=pff_ret_fisico_restriccion)
+
+        # Restriccion FOENS
+        def pff_cortada_restriccion(model, CFF):
+            return (model.pff_cortada[CFF] <= model.pff_declarada[CFF])
+        model.pff_cortada_constraint = Constraint(
+            model.CFF, rule=pff_cortada_restriccion)
+
+        def pf_cortada_restriccion(model, CF):
+            return (model.pf_cortada[CF] <= model.pf_req[CF])
+        model.pf_cortada_constraint = Constraint(
+            model.CF, rule=pf_cortada_restriccion)
+
+        logger.info('Restricciones de transmision.')
+        # Restricciones de transmision
+
+        def inyec(model, i):
+            return (model.inyeccion[i] == model.G[i] +
+                    sum(model.pi[OI, s]*model.bin_pi[i, OI] for OI in model.OI for s in model.s) +
+                    sum(model.pfi[CF, s]*model.bin_cfi[i, CF] for CF in model.CF for s in model.s) +
+                    sum(model.pff_iny_fisico[CFF]*model.bin_pffi[i, CFF] for CFF in model.CFF))
+        model.inyec_constraint = Constraint(model.i, rule=inyec)
+
+        def retiro(model, i):
+            return (model.retiro[i] == model.D[i] +
+                    sum(model.pr[OR, s]*model.bin_pr[i, OR] for OR in model.OR for s in model.s) +
+                    sum(model.pf_req[CF]*model.bin_cfr[i, CF] for CF in model.CF) +
+                    sum(model.pff_ret_fisico[CFF]*model.bin_pffr[i, CFF] for CFF in model.CFF) -
+                    0*sum(model.pf_cortada[CF]*model.bin_cfr[i, CF] for CF in model.CF) -
+                    0*sum(model.pf_pre_cortada[CF]*model.bin_cfr[i, CF] for CF in model.CF))
+        model.retiro_constraint = Constraint(model.i, rule=retiro)
+
+        # Los multiplicadore o variable duales de esta restriccion son los precios nodales
+        def balance_inyeccion_retiro(model, i):
+            return (model.inyeccion[i] + sum(model.Inc[c, i]*model.rtmw_c[c] for c in model.c) -  # Al dividir entre 100 Rc
+                    # toda la ec. se pasa a p.u.
+                    0.5*sum(((model.Inc[c, i]*model.rtmw_c[c])**2)
+                            * (model.Rc[c]/100) for c in model.c)
+                    == model.retiro[i])
+        model.balance_inyeccion_retiro_constraint = Constraint(
+            model.i, rule=balance_inyeccion_retiro)
+
+        def rtmw_min_restriccion(model, c):
+            return (model.rtmw_c[c] >= -model.rtmw_min[c])
+        model.rtmw_min_constraint = Constraint(
+            model.c, rule=rtmw_min_restriccion)
+
+        def rtmw_max_restriccion(model, c):
+            return (model.rtmw_c[c] <= model.rtmw_max[c])
+        model.rtmw_max_constraint = Constraint(
+            model.c, rule=rtmw_max_restriccion)
+
+        def flujo_potencia_actica(model, c):
+            return ((model.Xc[c])*model.rtmw_c[c]+sum(model.Inc[c, i]*model.ref_angular[i] for i in model.i) == 0)
+        model.flujo_potencia_actica_constraint = Constraint(
+            model.c, rule=flujo_potencia_actica)
+
+        # Máximas capacidades de trasferencia entre áreas de control
+        def eq_mct_ns_rule(model, inter):
+            if inter == 'ES':  # Maxima exportacion de El Salvador
+                return (-(model.DirF[inter]*model.rtmw_c[lin_mct[inter][0]]+model.DirF[inter]*model.rtmw_c[lin_mct[inter][1]]) +
+                        (model.DirF[inter]*model.rtmw_c[lin_mct[inter][2]]+model.DirF[inter]*model.rtmw_c[lin_mct[inter][3]])) <= model.Mct[inter, 'ns', PERIODO] + 0.001
+            elif inter == 'HON':  # Maxima importacion de Honduras
+                return (-(model.DirF[inter]*model.rtmw_c[lin_mct[inter][0]]+model.DirF[inter]*model.rtmw_c[lin_mct[inter][1]] +
+                          model.DirF[inter]*model.rtmw_c[lin_mct[inter][2]]) + (model.DirF[inter]*model.rtmw_c[lin_mct[inter][3]] +
+                                                                                model.DirF[inter]*model.rtmw_c[lin_mct[inter][4]])) <= model.Mct[inter, 'sn', PERIODO] + 0.001
+            else:
+                return sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct[inter]) <= model.Mct[inter, 'ns', PERIODO] + 0.001
+        model.eq_mct_ns = Constraint(model.inter, rule=eq_mct_ns_rule)
+
+        def eq_mct_sn_rule(model, inter):
+            if inter == 'ES':  # Maxima importacion de El Salvador
+                return (-(model.DirF[inter]*model.rtmw_c[lin_mct[inter][0]]+model.DirF[inter]*model.rtmw_c[lin_mct[inter][1]]) +
+                        (model.DirF[inter]*model.rtmw_c[lin_mct[inter][2]]+model.DirF[inter]*model.rtmw_c[lin_mct[inter][3]])) >= -model.Mct[inter, 'sn', PERIODO] + 0.00001
+            elif inter == 'HON':  # Maxima importacion de Honduras
+                return (-(model.DirF[inter]*model.rtmw_c[lin_mct[inter][0]]+model.DirF[inter]*model.rtmw_c[lin_mct[inter][1]] +
+                          model.DirF[inter]*model.rtmw_c[lin_mct[inter][2]]) + (model.DirF[inter]*model.rtmw_c[lin_mct[inter][3]] +
+                                                                                model.DirF[inter]*model.rtmw_c[lin_mct[inter][4]])) >= -model.Mct[inter, 'ns', PERIODO] + 0.00001
+            else:
+                return sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct[inter]) >= -model.Mct[inter, 'sn', PERIODO] + 0.00001
+        model.eq_mct_sn = Constraint(model.inter, rule=eq_mct_sn_rule)
+
+        model.dual = Suffix(direction=Suffix.IMPORT)
+
+        logger.info("Construcción del modelo terminada.")
+
+        ########################################### ORIGINAL #########
+        # opt = SolverFactory('ipopt')
+        # # opt.options['max_iter']= 10000
+        # result = opt.solve(model)
+        # model.solutions.store_to(result)
+
+        ############################################ MODIFICADO POR OSCAR ############
+
+        filename = path.basename(file).split('.')[0]
+        filepath = path.dirname(file)
+
+        try:
+
+            opt = SolverFactory('ipopt')  # TODO
+
+            logger.info(
+                "Inicio de la optimización para el periodo {}...".format(p_exec))
+
+            result = opt.solve(
+                model, logfile=f'log/solver_{filename}_{p_exec}.log', tee=True)
+
+            model.solutions.store_to(result)
+
+            result.write(
+                filename=f"{APPDIRS['DATA']}/results_{filename}_periodo_{p_exec}.json",
+                format='json')
+            logger.info(
+                "Solucion encontrada para el periodo{}...".format(p_exec))
+
+        except Exception as e:
+            logger.error("No se ejecutó el problema de optimización")
+            logger.exception("Error: {}".format(e))
+
+            return
+
+        # Cálculo de Precios Nodales
+        # =============================================================================
+        logger.info("Calculando Precios Nodales. Periodo:" + str(PERIODO))
+        Sigma = zeros(nb)
+        for i in model.i:
+            Sigma[i] = model.dual[model.balance_inyeccion_retiro_constraint[i]]
+
+        # Construcción de array para grabar
+        # =============================================================================
+        flujos = DataFrame()
+        flujos['Periodo'] = set_periodo(nbr, PERIODO)
+        flujos['BUS I'] = brnames['BUS I']
+        flujos['BUS J'] = brnames['BUS J']
+        flujos['CKT'] = brnames['CKT']
+        f = array(list(model.rtmw_c.get_values().values()))
+        perdidas = zeros(nbr)
+        for c in model.c:
+            perdidas[c] = (f[c]**2)*rc[c]/100
+        flujos['Flujo'] = f
+        flujos['Perdidas'] = perdidas
+        # Guarda los resultados con los anteriores
+        flujos_t = concat([flujos_t, flujos])
+
+        pon = DataFrame()
+        result_inyeccion = array(list(model.inyeccion.get_values().values()))
+        result_retiro = array(list(model.retiro.get_values().values()))
+        pon['Periodo'] = set_periodo(nb, PERIODO)
+        pon['nodo'] = bus
+        pon['Precio Exante'] = Sigma*-1
+        # Guarda los resultados con los anteriores
+        pon_t = concat([pon_t, pon])
+        # print(pon)
+
+        iep = DataFrame()
+        iep['Periodo'] = set_periodo(nb, PERIODO)
+        iep['nodo'] = bus
+        iep['Inyeccion'] = result_inyeccion
+        iep['Retiro'] = result_retiro
+        # Guarda los resultados con los anteriores
+        iep_t = concat([iep_t, iep])
+
+        result_pff_iny = array(
+            list(model.pff_iny_fisico.get_values().values()))
+        result_pff_ret = array(
+            list(model.pff_ret_fisico.get_values().values()))
+        result_pr = setvariable_p(
+            array(list(model.pr.get_values().values())), NOR)
+        result_pi = setvariable_p(
+            array(list(model.pi.get_values().values())), NOI)
+        result_pfi = setvariable_p(
+            array(list(model.pfi.get_values().values())), NCF)
+        result_pffr = setvariable_p(
+            array(list(model.pffr.get_values().values())), NCFF)
+        result_pffi = setvariable_p(
+            array(list(model.pffi.get_values().values())), NCFF)
+        result_pfft = setvariable_p(
+            array(list(model.pfft.get_values().values())), NCFF)
+
+        result_foo_r = DataFrame()
+        result_foo_r['Periodo'] = ex_oor['periodo']
+        result_foo_r['N°'] = ex_oor['N°']
+        result_foo_r['Pr Bloque 1'] = result_pr[:, 0]
+        result_foo_r['Pr Bloque 2'] = result_pr[:, 1]
+        result_foo_r['Pr Bloque 3'] = result_pr[:, 2]
+        result_foo_r['Pr Bloque 4'] = result_pr[:, 3]
+        result_foo_r['Pr Bloque 5'] = result_pr[:, 4]
+        # Guarda los resultados con los anteriores
+        result_foo_r_t = concat([result_foo_r_t, result_foo_r])
+
+        result_foo_i = DataFrame()
+        result_foo_i['Periodo'] = ex_ooi['periodo']
+        result_foo_i['N°'] = ex_ooi['N°']
+        result_foo_i['Pi Bloque 1'] = result_pi[:, 0]
+        result_foo_i['Pi Bloque 2'] = result_pi[:, 1]
+        result_foo_i['Pi Bloque 3'] = result_pi[:, 2]
+        result_foo_i['Pi Bloque 4'] = result_pi[:, 3]
+        result_foo_i['Pi Bloque 5'] = result_pi[:, 4]
+        # Guarda los resultados con los anteriores
+        result_foo_i_t = concat([result_foo_i_t, result_foo_i])
+
+        result_fof = DataFrame()
+        result_fof['Periodo'] = ex_cf['periodo']
+        result_fof['N°'] = ex_cf['N°']
+        result_fof['Pfi Bloque 1'] = result_pfi[:, 0]
+        result_fof['Pfi Bloque 2'] = result_pfi[:, 1]
+        result_fof['Pfi Bloque 3'] = result_pfi[:, 2]
+        result_fof['Pfi Bloque 4'] = result_pfi[:, 3]
+        result_fof['Pfi Bloque 5'] = result_pfi[:, 4]
+        # Guarda los resultados con los anteriores
+        result_fof_t = concat([result_fof_t, result_fof])
+
+        result_foff = DataFrame()
+        result_foff['Periodo'] = ex_cnfff['periodo']
+        result_foff['N°'] = ex_cnfff['N°']
+        result_foff['Pffr Bloque 1'] = result_pffr[:, 0]
+        result_foff['Pffr Bloque 2'] = result_pffr[:, 1]
+        result_foff['Pffr Bloque 3'] = result_pffr[:, 2]
+        result_foff['Pffr Bloque 4'] = result_pffr[:, 3]
+        result_foff['Pffr Bloque 5'] = result_pffr[:, 4]
+        result_foff['Pffi Bloque 1'] = result_pffi[:, 0]
+        result_foff['Pffi Bloque 2'] = result_pffi[:, 1]
+        result_foff['Pffi Bloque 3'] = result_pffi[:, 2]
+        result_foff['Pffi Bloque 4'] = result_pffi[:, 3]
+        result_foff['Pffi Bloque 5'] = result_pffi[:, 4]
+        result_foff['Pfft Bloque 1'] = result_pfft[:, 0]
+        result_foff['Pfft Bloque 2'] = result_pfft[:, 1]
+        result_foff['Pfft Bloque 3'] = result_pfft[:, 2]
+        result_foff['Pfft Bloque 4'] = result_pfft[:, 3]
+        result_foff['Pfft Bloque 5'] = result_pfft[:, 4]
+        # Guarda los resultados con los anteriores
+        result_foff_t = concat([result_foff_t, result_foff])
+
+        foo_ret_iny = DataFrame()
+        foo_ret_iny['Periodo'] = ex_cnfff['periodo']
+        foo_ret_iny['N°'] = ex_cnfff['N°']
+        foo_ret_iny['Inyeccion'] = result_pff_iny
+        foo_ret_iny['Retiro'] = result_pff_ret
+        # Guarda los resultados con los anteriores
+        foo_ret_iny_t = concat([foo_ret_iny_t, foo_ret_iny])
+
+    logger.info("Escribiendo resultados en carpeta.")
+    filename = path.basename(file).split('.')
+    filepath = path.dirname(file)
+
+    if all_day:
+
+        new_filename = filename[0]+'_results.'+filename[1]
+        new_file = path.join(filepath, new_filename)
+    else:
+        new_filename = filename[0]+'_results_{}.'.format(p_exec)+filename[1]
+        new_file = path.join(filepath, new_filename)
+
+    writer = ExcelWriter(new_file)
+    flujos_t.to_excel(writer, 'IEP-RTR', index=False)
+    iep_t.to_excel(writer, 'IEP-TOTAL', index=False)
+    pon_t.to_excel(writer, 'PEXANTES', index=False)
+    result_foo_i_t.to_excel(writer, 'TOP-I', index=False)
+    result_foo_r_t.to_excel(writer, 'TOP-R', index=False)
+    result_fof_t.to_excel(writer, 'TCP-CF', index=False)
+    result_foff_t.to_excel(writer, 'TCP-CNFFF-1', index=False)
+    foo_ret_iny_t.to_excel(writer, 'TCP-CNFFF-2', index=False)
+    writer.save()
+
+    return 0
+
+
+if __name__ == "__main__":
+    setmodel()  # faltan argumentos

+ 1 - 0
qhandler/__init__.py

@@ -0,0 +1 @@
+from .queuehandler import QueueHandler

二進制
qhandler/__pycache__/__init__.cpython-37.pyc


二進制
qhandler/__pycache__/__init__.cpython-38.pyc


二進制
qhandler/__pycache__/queuehandler.cpython-37.pyc


二進制
qhandler/__pycache__/queuehandler.cpython-38.pyc


+ 22 - 0
qhandler/queuehandler.py

@@ -0,0 +1,22 @@
+import logging
+
+
+class QueueHandler(logging.Handler):
+    """Class to send logging records to a queue
+
+    It can be used from different threads
+    The ConsoleUi class polls this queue to display records in a ScrolledText widget
+    """
+    # Example from Moshe Kaplan: https://gist.github.com/moshekaplan/c425f861de7bbf28ef06
+    # (https://stackoverflow.com/questions/13318742/python-logging-to-tkinter-text-widget) is not thread safe!
+    # See https://stackoverflow.com/questions/43909849/tkinter-python-crashes-on-new-thread-trying-to-log-on-main-thread
+
+    def __init__(self, log_queue):
+        super().__init__()
+        self.log_queue = log_queue
+
+    def emit(self, record):
+        self.log_queue.put(record)
+
+    def flush(self):
+        pass

二進制
red/__pycache__/__init__.cpython-38.pyc


二進制
red/__pycache__/create.cpython-38.pyc


二進制
red/__pycache__/create1.cpython-38.pyc


二進制
red/__pycache__/makeBdc.cpython-38.pyc


二進制
red/__pycache__/read.cpython-38.pyc


+ 2 - 0
requirements.txt

@@ -4,3 +4,5 @@ pandas==1.1.0
 Pyomo==5.7
 scipy==1.5.2
 xlrd==1.2.0
+Pillow==7.2.0
+winshell

+ 5 - 0
run.bat

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

+ 120 - 0
spr.bat

@@ -0,0 +1,120 @@
+@::!/dos/rocks
+@echo off
+goto :init
+
+:header
+    echo %__NAME% v%__VERSION%
+    echo Sistema de Simulacion de Predespacho del MER
+    echo.
+    goto :eof
+
+:usage
+    echo USAGE:
+    echo   %__BAT_NAME% "INPUTFILE" "<PERIODO>" 
+    echo.
+    echo.  /?, --help           shows this help
+    echo.  /v, --version        shows the version
+    echo.  /e, --verbose        shows detailed output
+    echo.
+    echo.  Si no se especifica un periodo sel Sistema
+    echo.  ejecuta las 24 horas del dia [0-23]
+    goto :eof
+
+:version
+    if "%~1"=="full" call :header & goto :eof
+    echo %__VERSION%
+    goto :eof
+
+:missing_argument
+    call :header
+    call :usage
+    echo.
+    echo ****                           ****
+    echo ****    MISSING "INPUTFILE"    ****
+    echo ****                           ****
+    echo.
+    goto :eof
+
+:init
+    set "__NAME=%~n0"
+    set "__VERSION=1.0 beta"
+    set "__YEAR=2020"
+
+    set "__BAT_FILE=%~0"
+    set "__BAT_PATH=%~dp0"
+    set "__BAT_NAME=%~nx0"
+
+    set "OptHelp="
+    set "OptVersion="
+    set "OptVerbose="
+
+    set "InputFileArg="
+    set "PeriodoArg="
+
+
+:parse
+    if "%~1"=="" goto :validate
+
+
+    if /i "%~1"=="-h"         call :header & call :usage "%~2" & goto :end
+    if /i "%~1"=="--help"     call :header & call :usage "%~2" & goto :end
+
+
+    if /i "%~1"=="-v"         call :version      & goto :end
+    if /i "%~1"=="--version"  call :version full & goto :end
+
+    if not defined InputFileArg     set "InputFileArg=%~1"     & shift & goto :parse
+    if not defined PeriodoArg  set "PeriodoArg=%~1"  & shift & goto :parse
+
+    shift
+    goto :parse
+
+:validate
+    if not defined InputFileArg call :missing_argument & goto :end
+
+:main
+    if defined OptVerbose (
+        echo **** DEBUG IS ON
+    )
+
+    echo InputFileArg:    "%InputFileArg%"
+
+    if defined PeriodoArg      echo PeriodoArg: "%PeriodoArg%"
+    if not defined PeriodoArg set "PeriodoArg=23"
+    echo PeriodoArg   "%PeriodoArg%"
+
+
+    goto :runmodel
+    
+
+:runmodel
+    %LOCALAPPDATA%\Merelec\spr\mc3\python.exe main.py -i %InputFileArg% -p %PeriodoArg%
+
+
+:end
+    call :cleanup
+    exit /B
+
+:cleanup
+    REM The cleanup function is only really necessary if you
+    REM are _not_ using SETLOCAL.
+    set "__NAME="
+    set "__VERSION="
+    set "__YEAR="
+
+    set "__BAT_FILE="
+    set "__BAT_PATH="
+    set "__BAT_NAME="
+
+    set "OptHelp="
+    set "OptVersion="
+    set "OptVerbose="
+
+    set "InputFileArg="
+    set "InputFileArg2="
+    set "NamedFlag="
+
+    pause
+
+    goto :eof
+

+ 0 - 0
spr/__init__.py


二進制
spr/__pycache__/__init__.cpython-38.pyc


二進制
spr/__pycache__/runspr.cpython-38.pyc


二進制
spr/__pycache__/runthread.cpython-38.pyc


+ 34 - 0
spr/runspr.py

@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+"""
+Modulo principal para ejecutar el modelo de predespacho regional
+"""
+
+import logging
+import sys
+
+from presdespacho import setmodel
+
+logger = logging.getLogger('spr.run')
+
+
+def main(file, periodo, full_day=True):
+    """Ejecuta la Simulación del Predespacho Regional."""
+    try:
+        # Check if solver 'ipopt' is on path
+        logger.info("Inicio de la ejecucion del modelo de predespacho")
+        setmodel(file, periodo, full_day)
+
+    except Exception as e:
+        logger.error(e)
+        return
+
+
+if __name__ == "__main__":
+    ch = logging.StreamHandler()
+
+    logger.addHandler(ch)
+    if len(sys.argv) < 2:
+        print("Se debe incluir un archivo")
+
+    else:
+        main(sys.argv[1])

+ 33 - 0
spr/runthread.py

@@ -0,0 +1,33 @@
+import logging
+import threading
+import time
+
+from pkg_resources import run_script
+
+import spr.runspr as runspr
+
+logger = logging.getLogger("spr.thread")
+
+
+class RunSprThread(threading.Thread):
+    def __init__(self, group=None, target=None, name=None,
+                 args=(), kwargs=None, *, daemon=None):
+        super(RunSprThread, self).__init__(group=group,
+                                           target=target,
+                                           name=name,
+                                           daemon=daemon)
+        self._stop_event = threading.Event()
+        self.args = args
+        self.kwargs = kwargs
+        return
+
+    def run(self):
+
+        t = time.time()
+        runspr.main(*self.args)
+        elapsed_time = time.time() - t
+        et = time.strftime("%H:%M:%S", time.gmtime(elapsed_time))
+        logger.info('Tiempo de ejecución %s' % et)
+
+    def stop(self):
+        self._stop_event.set()

二進制
utils/__pycache__/__init__.cpython-38.pyc


二進制
utils/__pycache__/arr2dict.cpython-38.pyc


二進制
utils/__pycache__/idx_brch.cpython-38.pyc


二進制
utils/__pycache__/solver_checker.cpython-38.pyc


+ 11 - 0
utils/solver_checker.py

@@ -0,0 +1,11 @@
+import shutil
+
+from common.exceptions import SolverNotFoundError
+
+
+def check_solver():
+    # Check if solver 'ipopt' is on path
+    solver_path = shutil.which('ipopt')
+
+    if not solver_path:
+        raise SolverNotFoundError