presdespacho.py 32 KB

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