presdespacho.py 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. from __future__ import division
  2. import logging
  3. import traceback
  4. from os import path
  5. import sys
  6. import pandas as pd
  7. import pyutilib.subprocess.GlobalData
  8. from numpy import array, zeros
  9. from pandas import DataFrame, ExcelWriter
  10. from pyomo.environ import *
  11. from pyomo.environ import SolverFactory
  12. from pyomo.kernel import value
  13. from common.data import APPDIRS
  14. from mct.makeMCT import linmct, readmct, set_dir_flujo
  15. from red.orderC import nodec
  16. from red.create import *
  17. from red.create1 import *
  18. from red.makeBdc import makeBdc
  19. from red.read import excel2net
  20. from utils.arr2dict import arr2dict
  21. pyutilib.subprocess.GlobalData.DEFINE_SIGNAL_HANDLERS_DEFAULT = False
  22. logger = logging.getLogger('spr.run.modelo')
  23. def setmodel(file, p_exec, all_day=True):
  24. # Determinar si se ejecuta todo el día o solo un período en específico
  25. if all_day:
  26. min = 0
  27. max = p_exec + 1
  28. logger.info("Se ejecuta el Modelo de Predespacho para las 24 horas")
  29. else:
  30. min = p_exec
  31. max = p_exec + 1
  32. logger.info(
  33. "Se ejecuta el Modelo de Predespacho para la hora {}".format(p_exec))
  34. logger.info("Modelo de Predespacho Regional")
  35. logger.info("Mercados Eléctricos de Centroamérica (c) 2020")
  36. # ============================================================================
  37. # Importación de datos desde archivo Excel
  38. # ============================================================================
  39. # Parametros de la linea
  40. logger.info("Inicio Predespacho Regional")
  41. logger.info("Leyendo información de RTR...")
  42. net_t = excel2net(file)
  43. dirf = set_dir_flujo()
  44. mct = readmct(file)
  45. # Informacion de los despachos nacionales
  46. dg_t = read_D_G(file)
  47. # Ofertas de todos los periodos
  48. ex_cnfff_t = readofertas_cnfffs(file)
  49. ex_ooi_t = readofertas_oois(file)
  50. ex_oor_t = readofertas_oors(file)
  51. ex_cf_t = readofertas_cfs(file)
  52. # Dataframe para almacenar la informacion de cada predespacho
  53. flujos_t = DataFrame()
  54. iep_t = DataFrame()
  55. pon_t = DataFrame()
  56. result_foo_i_t = DataFrame()
  57. result_foo_r_t = DataFrame()
  58. result_fof_t = DataFrame()
  59. result_foff_t = DataFrame()
  60. # El range del for se modifica dependiendo los periodos que se quieren correr.
  61. for PERIODO in range(min, max):
  62. logger.info("Inicio de la ejecución para el periodo {}".format(PERIODO))
  63. net=net_t[net_t.periodo.isin([PERIODO])].copy()
  64. net.reset_index(drop=True, inplace=True)
  65. net.drop(['periodo'], axis='columns', inplace=True)
  66. bus = setbus(net)#Nodos
  67. branch = setbranch(net, bus)#Set lineas
  68. bu = branch[:, 5]#potenica max de la linea
  69. bl = branch[:, 6]#potenica min de la linea
  70. xc = branch[:,3]#Reactancia de la linea
  71. rc = branch[:,4]#Resistencia de la linea
  72. nb = bus.shape[0] #Numero de nodos
  73. nbr = branch.shape[0]#Numero de lineas
  74. A = makeBdc(bus, branch)#Matriz incidente
  75. brnames = branchnames(bus, branch)#Nombre de las lineas
  76. inc = A.toarray()*-1
  77. # Lineas para límites de MCT
  78. br_t = brnames['Total'].to_numpy()
  79. lin_mct = linmct(br_t)
  80. logger.info("Leyendo información de los despacho nacionales.")
  81. # Dependiendo de los valores de la columna periodo del df son los valores que toma
  82. dg = dg_t[dg_t.periodo.isin([PERIODO])]
  83. # Resetea valores de ordenamiento del DF
  84. dg.reset_index(drop=True, inplace=True)
  85. # Ordena los valores que tiene segun los nodos de rtr
  86. dg_n = set_dgnacional(bus, dg)
  87. logger.info("Leyendo información de ofertas.")
  88. # Funcion leer contratos no firmes fisicos flexibles
  89. # Dependiendo de los valores de la columna periodo del df son los valores que toma
  90. ex_cnfff = ex_cnfff_t[ex_cnfff_t.periodo.isin([PERIODO])]
  91. # Resetea valores de ordenamiento del DF
  92. ex_cnfff.reset_index(drop=True, inplace=True)
  93. # Energia declarada con respecto al nodo
  94. vnfff_ed = setvariable(ex_cnfff['energía_dec'])
  95. # Magnitud de energia ofertada -flexibilizacion
  96. vnfff_m_i = setvariable_s(
  97. ex_cnfff[['magnitud_i1', 'magnitud_i2', 'magnitud_i3', 'magnitud_i4', 'magnitud_i5']])
  98. vnfff_m_r = setvariable_s(
  99. ex_cnfff[['magnitud_r1', 'magnitud_r2', 'magnitud_r3', 'magnitud_r4', 'magnitud_r5']])
  100. vnfff_m_cvt = setvariable_s(
  101. ex_cnfff[['magnitud_cvt1', 'magnitud_cvt2', 'magnitud_cvt3', 'magnitud_cvt4', 'magnitud_cvt5']])
  102. # Precio de la ofertas de inyeccion
  103. p_cnfffi = setvariable_s(
  104. ex_cnfff[['precio_i1', 'precio_i2', 'precio_i3', 'precio_i4', 'precio_i5']])
  105. # Precio de la ofertas de retiro
  106. p_cnfffr = setvariable_s(
  107. ex_cnfff[['precio_r1', 'precio_r2', 'precio_r3', 'precio_r4', 'precio_r5']])
  108. # Precio de la ofertas de inyeccion
  109. p_cnfffcvt = setvariable_s(
  110. ex_cnfff[['precio_cvt1', 'precio_cvt2', 'precio_cvt3', 'precio_cvt4', 'precio_cvt5']])
  111. # Precio de la ofertas de inyeccion
  112. k_cnfffcvt = setvariable(ex_cnfff['k'])
  113. NCFF = ex_cnfff.shape[0] # Numero de contratos firmes
  114. var_bin_cnfffr = MATRIZ_VNFFF_R(bus, ex_cnfff)
  115. var_bin_cnfffi = MATRIZ_VNFFF_I(bus, ex_cnfff)
  116. dem = setvariable(dg_n['Demanda'])
  117. gen = setvariable(dg_n['Generacion'])
  118. # Funcion leer parametros oferta de oportunidad inyeccion
  119. # Dependiendo de los valores de la columna periodo del df son los valores que toma
  120. ex_ooi = ex_ooi_t[ex_ooi_t.periodo.isin([PERIODO])]
  121. # Resetea valores de ordenamiento del DF
  122. ex_ooi.reset_index(drop=True, inplace=True)
  123. vooi_m = setvariable_s(ex_ooi[['magnitud_ooi1', 'magnitud_ooi2', 'magnitud_ooi3',
  124. 'magnitud_ooi4', 'magnitud_ooi5']]) # Ofertas con respecto al nodo
  125. p_ooi = setvariable_s(ex_ooi[['precio_ooi1', 'precio_ooi2', 'precio_ooi3',
  126. 'precio_ooi4', 'precio_ooi5']]) # Precio de la ofertas
  127. NOI = ex_ooi.shape[0] # Numero de ofertas de inyeccion
  128. var_bin_ooi = MATRIZ_OOI(bus, ex_ooi)
  129. # Funcion leer parametros oferta de oportunidad retiro
  130. ex_oor = ex_oor_t[ex_oor_t.periodo.isin([PERIODO])]
  131. # Resetea valores de ordenamiento del DF
  132. ex_oor.reset_index(drop=True, inplace=True)
  133. voor_m = setvariable_s(ex_oor[['magnitud_oor1', 'magnitud_oor2', 'magnitud_oor3',
  134. 'magnitud_oor4', 'magnitud_oor5']]) # Ofertas con respecto al nodo
  135. # Precio de la ofertas - flexibilizacion
  136. p_oor = setvariable_s(
  137. ex_oor[['precio_oor1', 'precio_oor2', 'precio_oor3', 'precio_oor4', 'precio_oor5']])
  138. NOR = ex_oor.shape[0] # Numero de ofertas de retiro
  139. var_bin_oor = MATRIZ_OOR(bus, ex_oor)
  140. # Funcion leer parametros contratos firmes
  141. # Dependiendo de los valores de la columna periodo del df son los valores que toma
  142. ex_cf = ex_cf_t[ex_cf_t.periodo.isin([PERIODO])]
  143. # Resetea valores de ordenamiento del DF
  144. ex_cf.reset_index(drop=True, inplace=True)
  145. # Energia declarada con respecto al nodo
  146. vcf_ed = setvariable(ex_cf['energía_dec'])
  147. # Potencia requerida con respecto al nodo
  148. vcf_pr = setvariable(ex_cf['potencia_req'])
  149. # Magnitud de energia ofertada -flexibilizacion
  150. vcf_m = setvariable_s(
  151. ex_cf[['magnitu_cf1', 'magnitu_cf2', 'magnitu_cf3', 'magnitu_cf4', 'magnitu_cf5']])
  152. # Precio de la ofertas
  153. vcf_p = setvariable_s(
  154. ex_cf[['precio_cf1', 'precio_cf2', 'precio_cf3', 'precio_cf4', 'precio_cf5']])
  155. NCF = ex_cf.shape[0] # Numero de contratos firmes
  156. var_bin_cfr = MATRIZ_CFR(bus, ex_cf)
  157. var_bin_cfi = MATRIZ_CFI(bus, ex_cf)
  158. # Inicio del modelo de optimización
  159. model = ConcreteModel()
  160. # sets
  161. model.i = Set(initialize=range(0, nb)) # numero de nodos
  162. model.c = Set(initialize=range(0, nbr)) # Numero de lineas
  163. # numero de ofertas de oportuniddad retiro
  164. model.OR = Set(initialize=range(0, NOR))
  165. # numero de ofertas de oportunidad inyeccion
  166. model.OI = Set(initialize=range(0, NOI))
  167. # numero de ofertas de CNFFF
  168. model.CFF = Set(initialize=range(0, NCFF))
  169. # numero de ofertas de contratos firmes
  170. model.CF = Set(initialize=range(0, NCF))
  171. model.s = Set(initialize=range(0, 5)) # Numero de bloques
  172. model.inter = Set(initialize=lin_mct.keys()) # Interconexiones
  173. # Sentidos de interconexiones
  174. model.sen = Set(initialize=['sn', 'ns'])
  175. model.per = Set(initialize=range(0, 24)) # numero de periodos
  176. # Parametros
  177. # Parametros de la red
  178. model.rtmw_min = Param(model.c, initialize=dict(enumerate(bl)))
  179. model.rtmw_max = Param(model.c, initialize=dict(enumerate(bu)))
  180. model.Inc = Param(model.c, model.i, initialize=arr2dict(inc))
  181. model.Xc = Param(model.c, initialize=dict(enumerate(xc)))
  182. model.Rc = Param(model.c, initialize=dict(enumerate(rc)))
  183. # Parametros de los predespachos nacionales
  184. model.D = Param(model.i, initialize=dict(enumerate(dem)))
  185. model.G = Param(model.i, initialize=dict(enumerate(gen)))
  186. # Ofertas de oportunidad
  187. # Oferta de oportunidad de retiro
  188. # Oferta bloques 1
  189. model.fr = Param(model.OR, model.s, initialize=arr2dict(p_oor))
  190. model.pr_ofertado = Param(model.OR, model.s, initialize=arr2dict(
  191. voor_m)) # Magnitud de la oferta MW-h
  192. model.bin_pr = Param(
  193. model.i, model.OR, initialize=arr2dict(var_bin_oor))
  194. # Oferta de oportunidad de inyeccion
  195. # Precio de bloques - Oferta de oportunidad de inyeccion
  196. model.fi = Param(model.OI, model.s, initialize=arr2dict(p_ooi))
  197. model.pi_ofertado = Param(model.OI, model.s, initialize=arr2dict(
  198. vooi_m)) # Magnitud de la oferta MW-h
  199. model.bin_pi = Param(
  200. model.i, model.OI, initialize=arr2dict(var_bin_ooi))
  201. # Contratos firmes
  202. model.pf_declarada = Param(model.CF, initialize=dict(
  203. enumerate(vcf_ed))) # Energia declarada
  204. # Potencia requerida - Si no se flexbiliza deberian de ser igual la energia y la potencia
  205. model.pf_req = Param(model.CF, initialize=dict(enumerate(vcf_pr)))
  206. # Precio de flexibilidad de contrato
  207. # Precio de bloques - Contrato firme - Oferta de flexibilidad
  208. model.ffi = Param(model.CF, model.s, initialize=arr2dict(vcf_p))
  209. # Magnitud de la oferta - tiene que ser igual a la suma de la energia declarada
  210. model.pfi_ofertado = Param(
  211. model.CF, model.s, initialize=arr2dict(vcf_m))
  212. model.bin_cfi = Param(
  213. model.i, model.CF, initialize=arr2dict(var_bin_cfi))
  214. model.bin_cfr = Param(
  215. model.i, model.CF, initialize=arr2dict(var_bin_cfr))
  216. # Ofertas de flexibilidad de contratos fisicos flexibles
  217. # Ofertas de inyeccion
  218. model.pff_declarada = Param(
  219. model.CFF, initialize=dict(enumerate(vnfff_ed)))
  220. model.pffi_ofertado = Param(
  221. model.CFF, model.s, initialize=arr2dict(vnfff_m_i)) # Magnitud del bloque
  222. model.fffi = Param(model.CFF, model.s, initialize=arr2dict(
  223. p_cnfffi)) # Precio de inyeccion
  224. model.bin_pffi = Param(
  225. model.i, model.CFF, initialize=arr2dict(var_bin_cnfffi))
  226. # Oferta de retiro
  227. model.pffr_ofertado = Param(model.CFF, model.s, initialize=arr2dict(
  228. vnfff_m_r)) # Magnitud de bloque de retiro ofertado
  229. # Precio de bloques - Contrato no firme fisico flexible
  230. model.fffr = Param(model.CFF, model.s, initialize=arr2dict(p_cnfffr))
  231. model.bin_pffr = Param(
  232. model.i, model.CFF, initialize=arr2dict(var_bin_cnfffr))
  233. # Ofertad de pago maximo por CVT
  234. model.k = Param(model.CFF, initialize=dict(
  235. enumerate(k_cnfffcvt))) # Indicador de oferta
  236. model.pfft_ofertado = Param(model.CFF, model.s, initialize=arr2dict(
  237. vnfff_m_cvt)) # Magnitud del bloque
  238. model.ffft = Param(model.CFF, model.s, initialize=arr2dict(
  239. p_cnfffcvt)) # Precio de pago maximo CVT
  240. # Variabeles
  241. # Variable ofertas de oportunidad
  242. # Parte aceptada de cada bloques de las ofertas de oportunidad de retiro
  243. model.pr = Var(model.OR, model.s, domain=NonNegativeReals)
  244. # Parte aceptada de cada bloques de las ofertas de oportunidad de inyeccion
  245. model.pi = Var(model.OI, model.s, domain=NonNegativeReals)
  246. # Variables CF
  247. # Parte aceptada de cada bloques de las ofertas de flexibilidad de contratos firmes
  248. model.pfi = Var(model.CF, model.s, domain=NonNegativeReals)
  249. # Variables CNFFF
  250. # Parte aceptada de cada bloques de las oferta de flexibilidad de retiro
  251. model.pffr = Var(model.CFF, model.s, domain=NonNegativeReals)
  252. # Parte aceptada de cada bloques de las ofertas de flexibilidad de inyección de los contratos físicos flexibles
  253. model.pffi = Var(model.CFF, model.s, domain=NonNegativeReals)
  254. # Parte aceptada de cada bloques de las oferta de pago máximo de CVT de los contratos físicos flexibles
  255. model.pfft = Var(model.CFF, model.s, domain=NonNegativeReals)
  256. # Componente fisica de energia PERIODOria de inyeecion
  257. model.pff_iny_fisico = Var(model.CFF, domain=NonNegativeReals)
  258. # Componente fisica de energia PERIODOria de retiro
  259. model.pff_ret_fisico = Var(model.CFF, domain=NonNegativeReals)
  260. # Variables FOENS
  261. # Energia firme de lo CF
  262. model.pf_cortada = Var(model.CF, domain=NonNegativeReals)
  263. model.pf_pre_cortada = Var(model.CF, domain=NonNegativeReals)
  264. # Energia firme de los CNFFF
  265. model.pff_cortada = Var(model.CFF, domain=NonNegativeReals)
  266. model.fens = Var()
  267. # Variable problema de optimizacion
  268. # Inyeccion por nodo
  269. model.inyeccion = Var(model.i, domain=NonNegativeReals)
  270. model.retiro = Var(model.i, domain=NonNegativeReals) # Retiro por nodo
  271. model.ref_angular = Var(model.i) # Fase del voltaje en el nodo
  272. model.rtmw_c = Var(model.c) # Flujo de potencia actica por linea
  273. # Máximas Capacidades de Trasferencia
  274. # Maxima transferenica(interconexion,sentido,periodo)
  275. model.Mct = Param(model.per, model.inter, model.sen, initialize=mct.MCT.to_dict(), default=300, mutable=True)
  276. model.DirF = Param(model.inter, initialize=dirf)
  277. logger.info("Ecuación de Función Objetivo Max.")
  278. def objfunc(model):
  279. return ((sum(model.fr[OR, s]*model.pr[OR, s] for OR in model.OR for s in model.s) - # ┌ FOO
  280. # └
  281. sum(model.fi[OI, s]*model.pi[OI, s] for OI in model.OI for s in model.s) -
  282. # [ FOF
  283. sum(model.ffi[CF, s]*model.pfi[CF, s] for CF in model.CF for s in model.s) +
  284. # ┌
  285. sum(model.fffr[CFF, s]*model.pffr[CFF, s] for CFF in model.CFF for s in model.s) -
  286. # │ FOFF
  287. sum(model.fffi[CFF, s]*model.pffi[CFF, s] for CFF in model.CFF for s in model.s) +
  288. # └
  289. sum(model.ffft[CFF, s]*model.pfft[CFF, s]
  290. for CFF in model.CFF for s in model.s))) # -
  291. # ┌ FOENS
  292. # 0*model.fens*sum(model.pf_cortada[CF] for CF in model.CF) -
  293. # 0*model.fens*0.5*sum(model.pff_cortada[CFF] for CFF in model.CFF))) # └
  294. model.OBJ = Objective(rule=objfunc, sense=maximize)
  295. logger.info("Restricciones del Modelo de Optimización. ")
  296. # Esta restricción no es utilizada y se encarga de efectuar la reducción
  297. # de los contratos firmes (idem FOENS línea 327)
  298. # def fens_restriccion(model):
  299. # if NOR == 0 & NCF == 0 & NCFF > 0:
  300. # return model.fens == 3*max(model.fffr[CFF, s] for CFF in model.CFF for s in model.s)
  301. # elif NOR == 0 & NCF > 0 & NCFF == 0:
  302. # return model.fens == 3*max(model.ffi[CF, s] for CF in model.CF for s in model.s)
  303. # elif NOR == 0 & NCF > 0 & NCFF > 0:
  304. # return model.fens == 3*max(max(model.ffi[CF, s] for CF in model.CF for s in model.s),
  305. # max(model.fffr[CFF, s] for CFF in model.CFF for s in model.s))
  306. # elif NOR > 0 & NCF == 0 & NCFF == 0:
  307. # return model.fens == 3*max(model.fr[OR, s] for OR in model.OR for s in model.s)
  308. # elif NOR > 0 & NCF == 0 & NCFF > 0:
  309. # return model.fens == 3*max(max(model.fr[OR, s] for OR in model.OR for s in model.s),
  310. # max(model.fffr[CFF, s] for CFF in model.CFF for s in model.s))
  311. # elif NOR > 0 & NCF > 0 & NCFF == 0:
  312. # return model.fens == 3*max(max(model.fr[OR, s] for OR in model.OR for s in model.s),
  313. # max(model.ffi[CF, s] for CF in model.CF for s in model.s))
  314. # elif NOR > 0 & NCF > 0 & NCFF > 0:
  315. # return model.fens == 3*max(max(model.fr[OR, s] for OR in model.OR for s in model.s),
  316. # max(model.fffr[CFF, s]
  317. # for CFF in model.CFF for s in model.s),
  318. # max(model.ffi[CF, s] for CF in model.CF for s in model.s))
  319. # model.fens_constraint = Constraint(rule=fens_restriccion)
  320. # Restrecciones FOO
  321. def pi_restriccion(model, OI, s):
  322. return ((model.pi[OI, s] <= model.pi_ofertado[OI, s]))
  323. model.pi_constraint = Constraint(
  324. model.OI, model.s, rule=pi_restriccion)
  325. def pr_restriccion(model, OR, s):
  326. return ((model.pr[OR, s] <= model.pr_ofertado[OR, s]))
  327. model.pr_constraint = Constraint(
  328. model.OR, model.s, rule=pr_restriccion)
  329. # Restricciones FOF
  330. def pfi_restriccion(model, CF, s):
  331. return (model.pfi[CF, s] <= model.pfi_ofertado[CF, s])
  332. model.pfi_constraint = Constraint(
  333. model.CF, model.s, rule=pfi_restriccion)
  334. # Restricciones FOFF
  335. def pffr_restriccion(model, CFF, s):
  336. return (model.pffr[CFF, s] <= model.pffr_ofertado[CFF, s])
  337. model.pffr_constraint = Constraint(
  338. model.CFF, model.s, rule=pffr_restriccion)
  339. def pffi_restriccion(model, CFF, s):
  340. return (model.pffi[CFF, s] <= model.pffi_ofertado[CFF, s])
  341. model.pffi_constraint = Constraint(
  342. model.CFF, model.s, rule=pffi_restriccion)
  343. if (model.k[CFF] == 0 for CFF in model.CFF):
  344. def pfft_restriccion(model, CFF, s):
  345. # if model.k[CFF] ==0:
  346. return (model.pfft[CFF, s] <= model.pfft_ofertado[CFF, s])
  347. model.pfft_constraint = Constraint(
  348. model.CFF, model.s, rule=pfft_restriccion)
  349. # K(cff) vale 0 si hay oferta de pago maximo por CVT
  350. def pff_iny_fisico_restriccion(model, CFF):
  351. if model.k[CFF] == 0:
  352. 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))
  353. elif model.k[CFF] == 1:
  354. return (model.pff_iny_fisico[CFF] == model.pff_declarada[CFF] - sum(model.pffr[CFF, s] for s in model.s))
  355. model.pff_iny_fisico_constraint = Constraint(
  356. model.CFF, rule=pff_iny_fisico_restriccion)
  357. def pff_ret_fisico_restriccion(model, CFF):
  358. if model.k[CFF] == 0:
  359. 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))
  360. elif model.k[CFF] == 1:
  361. return (model.pff_ret_fisico[CFF] == model.pff_declarada[CFF] - model.pff_cortada[CFF] - sum(model.pffi[CFF, s] for s in model.s))
  362. model.pff_ret_fisico_constraint = Constraint(
  363. model.CFF, rule=pff_ret_fisico_restriccion)
  364. # Restriccion FOENS
  365. def pff_cortada_restriccion(model, CFF):
  366. return (model.pff_cortada[CFF] <= model.pff_declarada[CFF])
  367. model.pff_cortada_constraint = Constraint(
  368. model.CFF, rule=pff_cortada_restriccion)
  369. def pf_cortada_restriccion(model, CF):
  370. return (model.pf_cortada[CF] <= model.pf_req[CF])
  371. model.pf_cortada_constraint = Constraint(
  372. model.CF, rule=pf_cortada_restriccion)
  373. logger.info('Restricciones de transmision.')
  374. # Restricciones de transmision
  375. def inyec(model, i):
  376. return (model.inyeccion[i] == model.G[i] +
  377. sum(model.pi[OI, s]*model.bin_pi[i, OI] for OI in model.OI for s in model.s) +
  378. sum(model.pfi[CF, s]*model.bin_cfi[i, CF] for CF in model.CF for s in model.s) +
  379. sum(model.pff_iny_fisico[CFF]*model.bin_pffi[i, CFF] for CFF in model.CFF))
  380. model.inyec_constraint = Constraint(model.i, rule=inyec)
  381. def retiro(model, i):
  382. return (model.retiro[i] == model.D[i] +
  383. sum(model.pr[OR, s]*model.bin_pr[i, OR] for OR in model.OR for s in model.s) +
  384. sum(model.pf_req[CF]*model.bin_cfr[i, CF] for CF in model.CF) +
  385. sum(model.pff_ret_fisico[CFF]*model.bin_pffr[i, CFF] for CFF in model.CFF) -
  386. 0*sum(model.pf_cortada[CF]*model.bin_cfr[i, CF] for CF in model.CF) -
  387. 0*sum(model.pf_pre_cortada[CF]*model.bin_cfr[i, CF] for CF in model.CF))
  388. model.retiro_constraint = Constraint(model.i, rule=retiro)
  389. # Los multiplicadore o variable duales de esta restriccion son los precios nodales
  390. def balance_inyeccion_retiro(model, i):
  391. return (model.inyeccion[i] + sum(model.Inc[c, i]*model.rtmw_c[c] for c in model.c) - # Al dividir entre 100 Rc
  392. # toda la ec. se pasa a p.u.
  393. 0.5*sum(((model.Inc[c, i]*model.rtmw_c[c])**2)
  394. * (model.Rc[c]/100) for c in model.c)
  395. == model.retiro[i])
  396. model.balance_inyeccion_retiro_constraint = Constraint(
  397. model.i, rule=balance_inyeccion_retiro)
  398. def rtmw_min_restriccion(model, c):
  399. return (model.rtmw_c[c] >= -model.rtmw_min[c])
  400. model.rtmw_min_constraint = Constraint(
  401. model.c, rule=rtmw_min_restriccion)
  402. def rtmw_max_restriccion(model, c):
  403. return (model.rtmw_c[c] <= model.rtmw_max[c])
  404. model.rtmw_max_constraint = Constraint(
  405. model.c, rule=rtmw_max_restriccion)
  406. def flujo_potencia_actica(model, c):
  407. return ((model.Xc[c])*model.rtmw_c[c]+sum(model.Inc[c, i]*model.ref_angular[i] for i in model.i) == 0)
  408. model.flujo_potencia_actica_constraint = Constraint(
  409. model.c, rule=flujo_potencia_actica)
  410. # Máximas capacidades de trasferencia entre áreas de control
  411. def eq_mct_ns_rule(model, inter):
  412. if inter=='IMP_TOT_SAL':#Maxima exportacion de El Salvador
  413. return ((sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['ELSHON']))-
  414. (sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['GUAELS']))) <= model.Mct[PERIODO, inter, 'ns']
  415. elif inter=='EXP_TOT_GUA_NS':
  416. return ((sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['GUAHON'])) +
  417. (sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['GUAELS']))) <= model.Mct[PERIODO, inter, 'ns']
  418. elif inter=='IMP_TOT_HON':#Maxima importacion de Honduras
  419. return (-(sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['ELSHON'])) -
  420. (sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['GUAHON'])) +
  421. (sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['HONNIC']))) <= model.Mct[PERIODO, inter, 'sn']
  422. elif inter=='IMP_TOT_NIC':#Maxima exportacion de Nicaragua
  423. return ((sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['NICCRI'])) -
  424. (sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['HONNIC']))) <= model.Mct[PERIODO, inter, 'ns']
  425. elif inter=='IMP_TOT_CRI':#Maxima exportacion de Costa Rica
  426. return ((sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['NICCRI'])) +
  427. (sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['CRIPAN']))) <= model.Mct[PERIODO, inter, 'ns']
  428. elif inter=='IMP_TOT_PAN':
  429. return sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['CRIPAN']) <= model.Mct[PERIODO, inter, 'ns']
  430. else:
  431. return (sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct[inter])) <= model.Mct[PERIODO, inter, 'ns']
  432. model.eq_mct_ns = Constraint(model.inter, rule=eq_mct_ns_rule)
  433. def eq_mct_sn_rule(model, inter):
  434. if inter=='IMP_TOT_SAL':#Maxima importacion de El Salvador
  435. return ((sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['ELSHON'])) -
  436. (sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['GUAELS']))) >= -model.Mct[PERIODO, inter, 'sn']
  437. elif inter=='EXP_TOT_GUA_NS':
  438. return ((sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['GUAHON'])) +
  439. (sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['GUAELS']))) >= -model.Mct[PERIODO, inter, 'sn']
  440. elif inter=='IMP_TOT_HON':#Maxima importacion de Honduras
  441. return (-((sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['ELSHON'])) +
  442. (sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['GUAHON']))) +
  443. (sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['HONNIC']))) >= -model.Mct[PERIODO, inter, 'ns']
  444. elif inter=='IMP_TOT_NIC':#Maxima exportacion de Nicaragua
  445. return ((sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['NICCRI'])) -
  446. (sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['HONNIC']))) >= -model.Mct[PERIODO, inter, 'sn']
  447. elif inter=='IMP_TOT_CRI':#Maxima exportacion de Costa Rica
  448. return ((sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['NICCRI'])) +
  449. (sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['CRIPAN'])))>= -model.Mct[PERIODO, inter, 'sn']
  450. elif inter=='IMP_TOT_PAN':
  451. return sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct['CRIPAN']) >= -model.Mct[PERIODO, inter, 'sn']
  452. else:
  453. return (sum(model.DirF[inter]*model.rtmw_c[c] for c in lin_mct[inter])) >= -model.Mct[PERIODO, inter, 'sn']
  454. model.eq_mct_sn = Constraint(model.inter, rule=eq_mct_sn_rule)
  455. model.dual = Suffix(direction=Suffix.IMPORT)
  456. print("Construcción del modelo terminada. Periodo: "+str(PERIODO))
  457. opt = SolverFactory('ipopt')
  458. #opt.options['max_iter']= 10000
  459. result = opt.solve(model)
  460. model.solutions.store_to(result)
  461. # Cálculo de Precios Nodales
  462. # =============================================================================
  463. print("Calculando Precios Nodales. Periodo:" + str(PERIODO))
  464. Sigma = zeros(nb)
  465. for i in model.i:
  466. Sigma[i] = model.dual[model.balance_inyeccion_retiro_constraint[i]]
  467. # Construcción de array para grabar
  468. # =============================================================================
  469. flujos=DataFrame()
  470. flujos['Periodo']=set_periodo(nbr,PERIODO)
  471. flujos['BUS I'] = brnames['BUS I']
  472. flujos['BUS J'] = brnames['BUS J']
  473. flujos['CKT'] = brnames['CKT']
  474. f = array(list(model.rtmw_c.get_values().values()))
  475. perdidas=zeros(nbr)
  476. for c in model.c:
  477. perdidas[c]=(f[c]**2)*rc[c]/100
  478. flujos['Flujo'] = f
  479. flujos['Perdidas'] = perdidas
  480. flujos=flujos.round({'Flujo':3,'Perdidas':3})
  481. flujos_t=concat([flujos_t,flujos].copy())#Guarda los resultados con los anteriores
  482. pon = DataFrame()
  483. result_inyeccion = array(list(model.inyeccion.get_values().values()))
  484. result_retiro = array(list(model.retiro.get_values().values()))
  485. pon['Periodo']=set_periodo(nb,PERIODO)
  486. pon['Nodo']= bus
  487. pon['Precio Exante'] = Sigma*-1
  488. pon=pon.round({'Precio Exante':2})
  489. pon_t=concat([pon_t,pon]).copy()#Guarda los resultados con los anteriores
  490. #print(pon)
  491. iep=DataFrame()
  492. iep['Periodo']=set_periodo(nb,PERIODO)
  493. iep['nodo']= bus
  494. iep['Inyeccion'] = result_inyeccion
  495. iep['Retiro'] = result_retiro
  496. iep=iep.round({'Inyeccion':3,'Retiro':3})
  497. iep_t=concat([iep_t,iep]).copy()#Guarda los resultados con los anteriores
  498. result_pff_iny=array(list(model.pff_iny_fisico.get_values().values()))
  499. result_pff_ret=array(list(model.pff_ret_fisico.get_values().values()))
  500. result_pr = setvariable_p(array(list(model.pr.get_values().values())),NOR)
  501. result_pi = setvariable_p(array(list(model.pi.get_values().values())),NOI)
  502. result_pfi = setvariable_p(array(list(model.pfi.get_values().values())),NCF)
  503. result_pffr = setvariable_p(array(list(model.pffr.get_values().values())),NCFF)
  504. result_pffi = setvariable_p(array(list(model.pffi.get_values().values())),NCFF)
  505. result_pfft = setvariable_p(array(list(model.pfft.get_values().values())),NCFF)
  506. result_foo_r=DataFrame()
  507. result_foo_r['ID']=ex_oor['N°']
  508. result_foo_r['Fecha']=ex_oor['Fecha'].apply( lambda d : d.date() )
  509. result_foo_r['Periodo']=ex_oor['periodo']
  510. result_foo_r['Nodo']=ex_oor['nodo_oor']
  511. pais_foo_r=pd.concat([result_foo_r.set_index('Nodo'),nodec.set_index('ID_NODO')], axis=1, join='inner').reset_index()
  512. pex_foo_r=pd.concat([result_foo_r.set_index('Nodo'),pon.set_index('Nodo')], axis=1, join='inner').reset_index()
  513. result_foo_r.drop(['Nodo'], axis='columns', inplace=True)
  514. result_foo_r['Pais']=pais_foo_r['ID_AREA']
  515. result_foo_r['Nodo']=ex_oor['nodo_oor']
  516. result_foo_r['Precio Exante']=pex_foo_r['Precio Exante']
  517. result_foo_r['Agente']=ex_oor['Agente']
  518. result_foo_r['MW Predespachados']=result_pr[:,0] + result_pr[:,1] + result_pr[:,2]+result_pr[:,3]+result_pr[:,4]
  519. result_foo_r=result_foo_r.round({'MW Predespachados':3})
  520. result_foo_r_t=concat([result_foo_r_t,result_foo_r]).copy()#Guarda los resultados con los anteriores
  521. result_foo_i=DataFrame()
  522. result_foo_i['ID']=ex_ooi['N°']
  523. result_foo_i['Fecha']=ex_ooi['Fecha'].apply( lambda d : d.date() )
  524. result_foo_i['Periodo']=ex_ooi['periodo']
  525. result_foo_i['Nodo']=ex_ooi['nodo_i']
  526. pex_foo_i=pd.concat([result_foo_i.set_index('Nodo'),pon.set_index('Nodo')], axis=1, join='inner').reset_index()
  527. pais_foo_i=pd.concat([result_foo_i.set_index('Nodo'),nodec.set_index('ID_NODO')], axis=1, join='inner').reset_index()
  528. result_foo_i.drop(['Nodo'], axis='columns', inplace=True)
  529. result_foo_i['Pais']=pais_foo_i['ID_AREA']
  530. result_foo_i['Nodo']=ex_ooi['nodo_i']
  531. result_foo_i['Precio Exante']=pex_foo_i['Precio Exante']
  532. result_foo_i['Agente']=ex_ooi['Agente']
  533. result_foo_i['MW Predespachados']=result_pi[:,0]+result_pi[:,1]+result_pi[:,2]+result_pi[:,3]+result_pi[:,4]
  534. result_foo_i=result_foo_i.round({'MW Predespachados':3})
  535. result_foo_i_t=concat([result_foo_i_t,result_foo_i]).copy()#Guarda los resultados con los anteriores
  536. result_fof=DataFrame()
  537. result_fof['ID']=ex_cf['N°']
  538. result_fof['Fecha']=ex_cf['Fecha'].apply( lambda d : d.date() )
  539. result_fof['Periodo']=ex_cf['periodo']
  540. result_fof['Nodo Inyeccion']=ex_cf['nodo_cfi']
  541. pex_fof_i=pd.concat([result_fof.set_index('Nodo Inyeccion'),pon.set_index('Nodo')], axis=1, join='inner').reset_index()
  542. pais_fof_i=pd.concat([result_fof.set_index('Nodo Inyeccion'),nodec.set_index('ID_NODO')], axis=1, join='inner').reset_index()
  543. result_fof.drop(['Nodo Inyeccion'], axis='columns', inplace=True)
  544. result_fof['Pais Inyeccion']=pais_fof_i['ID_AREA']
  545. result_fof['Nodo Inyeccion']=ex_cf['nodo_cfi']
  546. result_fof['Precio Exante Inyeccion']=pex_fof_i['Precio Exante']
  547. result_fof['Agente Inyeccion']=ex_cf['agente_cfi']
  548. result_fof['Nodo Retiro']=ex_cf['nodo_cfr']
  549. pais_fof_r=pd.concat([result_fof.set_index('Nodo Retiro'),nodec.set_index('ID_NODO')], axis=1, join='inner').reset_index()
  550. pex_fof_r=pd.concat([result_fof.set_index('Nodo Retiro'),pon.set_index('Nodo')], axis=1, join='inner').reset_index()
  551. result_fof.drop(['Nodo Retiro'], axis='columns', inplace=True)
  552. result_fof['Pais Retiro']=pais_fof_r['ID_AREA']
  553. result_fof['Nodo Retiro']=ex_cf['nodo_cfr']
  554. result_fof['Precio Exante Retiro']=pex_fof_r['Precio Exante']
  555. result_fof['Agente Retiro']=ex_cf['agente_cfr']
  556. result_fof['MW Predespachados O.I. Flexibilidad']=result_pfi[:,0]+result_pfi[:,1]+result_pfi[:,2]+result_pfi[:,3]+result_pfi[:,4]
  557. result_fof['MW Predespachados Ret. Requerido']=ex_cf['potencia_req']
  558. result_fof=result_fof.round({'MW Predespachados O.I. Flexibilidad':3,'MW Predespachados Ret. Requerido':3})
  559. result_fof_t=concat([result_fof_t,result_fof]).copy()#Guarda los resultados con los anteriores
  560. result_foff=DataFrame()
  561. result_foff['ID']=ex_cnfff['N°']
  562. result_foff['Fecha']=ex_cnfff['Fecha'].apply( lambda d : d.date() )
  563. result_foff['Periodo']=ex_cnfff['periodo']
  564. result_foff['Nodo Inyeccion']=ex_cnfff['nodo_cnfffi']
  565. pex_foff_i=pd.concat([result_foff.set_index('Nodo Inyeccion'),pon.set_index('Nodo')], axis=1, join='inner').reset_index()
  566. pais_foff_i=pd.concat([result_foff.set_index('Nodo Inyeccion'),nodec.set_index('ID_NODO')], axis=1, join='inner').reset_index()
  567. result_foff.drop(['Nodo Inyeccion'], axis='columns', inplace=True)
  568. result_foff['Pais Inyeccion']=pais_foff_i['ID_AREA']
  569. result_foff['Nodo Inyeccion']=ex_cnfff['nodo_cnfffi']
  570. result_foff['Precio Exante Inyeccion']=pex_foff_i['Precio Exante']
  571. result_foff['Agente Inyeccion']=ex_cnfff['agente_cnfffi']
  572. result_foff['Nodo Retiro']=ex_cnfff['nodo_cnfffr']
  573. pais_foff_r=pd.concat([result_foff.set_index('Nodo Retiro'),nodec.set_index('ID_NODO')], axis=1, join='inner').reset_index()
  574. pex_foff_r=pd.concat([result_foff.set_index('Nodo Retiro'),pon.set_index('Nodo')], axis=1, join='inner').reset_index()
  575. result_foff.drop(['Nodo Retiro'], axis='columns', inplace=True)
  576. result_foff['Pais Retiro']=pais_foff_r['ID_AREA']
  577. result_foff['Nodo Retiro']=ex_cnfff['nodo_cnfffr']
  578. result_foff['Precio Exante Retiro']=pex_foff_r['Precio Exante']
  579. result_foff['Agente Retiro']=ex_cnfff['agente_cnfffr']
  580. result_foff['CVT']=result_foff['Precio Exante Retiro'] - result_foff['Precio Exante Inyeccion']
  581. result_foff['MW Predespachados CNFFF']=result_pfft[:,0]+result_pfft[:,1]+result_pfft[:,2]+result_pfft[:,3]+result_pfft[:,4]
  582. result_foff['MW Predespachados O.I. Flexibilidad']=result_pffi[:,0]+result_pffi[:,1]+result_pffi[:,2]+result_pffi[:,3]+result_pffi[:,4]
  583. result_foff['MW Predespachados O.R. Flexibilidad']=result_pffr[:,0]+result_pffr[:,1]+result_pffr[:,2]+result_pffr[:,3]+result_pffr[:,4]
  584. result_foff=result_foff.round({'CVT':2,'MW Predespachados CNFFF':3,'MW Predespachados O.R. Flexibilidad':3,'MW Predespachados O.I. Flexibilidad':3})
  585. result_foff_t=concat([result_foff_t,result_foff])#Guarda los resultados con los anteriores
  586. logger.info("Escribiendo resultados en carpeta.")
  587. filename = path.basename(file).split('.')
  588. filepath = path.dirname(file)
  589. if all_day:
  590. new_filename = filename[0]+'_results.'+filename[1]
  591. new_file = path.join(filepath, new_filename)
  592. else:
  593. new_filename = filename[0]+'_results_{}.'.format(p_exec)+filename[1]
  594. new_file = path.join(filepath, new_filename)
  595. writer=ExcelWriter(new_file)
  596. flujos_t.to_excel(writer,'IEP-RTR',index=False)
  597. iep_t.to_excel(writer,'IEP-TOTAL',index=False)
  598. pon_t.to_excel(writer,'PEXANTE',index=False)
  599. result_foo_i_t.to_excel(writer,'TOP-I',index=False)
  600. result_foo_r_t.to_excel(writer,'TOP-R',index=False)
  601. result_fof_t.to_excel(writer,'TCP-CF',index=False)
  602. result_foff_t.to_excel(writer,'TCP-CNFFF',index=False)
  603. writer.save()
  604. print("{:=^100}".format(""))
  605. print("{:^100}".format(" Script Finalizado "))
  606. print("{:^100}".format(" Mercados Eléctricos de Centroamérica (c) 2020 "))
  607. print("{:=^100}".format(""))
  608. return 0
  609. if __name__ == "__main__":
  610. setmodel() # faltan argumentos