Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,23 @@ O formato segue o [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/).

## [Nao Publicado]

## [1.12.0] - 2026-07-24

### Adicionado

- Leitor do arquivo `mlt.dat`, com as médias mensais de longo termo (MLT) de cada posto por mês do ano, através da nova classe `Mlt`. O conteúdo é exposto como um `DataFrame` na propriedade `valores`, com uma linha por mês e uma coluna por posto, em m³/s.
- Leitor do arquivo `renovaveis.csv`, com o cadastro dos parques eólicos equivalentes, através da nova classe `Renovaveis` e dos registros da família `PEE` (`PEECadastro`, `PEESubmercado`, `PEEConfiguracaoPeriodo`, `PEEPotenciaInstaladaPeriodo` e `PEEGeracaoPeriodoPatamarCenario`).

### Alterado

- Versão mínima de `cfinterface` elevada para `1.10.1`.

### Corrigido

- O registro `IA` do `dadger` lia os limites de intercâmbio por patamar, mas não os expunha, de forma que `ia(df=True)` os omitia. Adicionadas as propriedades `limite_de_para` e `limite_para_de`.
- O método `ue` do `Dadger` retornava os dados do registro `UH` em vez do registro `UE`.
- Precisão decimal insuficiente (`decimal_digits=0`) nos limites de intercâmbio do registro `IA`, que arredondava para inteiro valores fracionários na escrita (round-trip). Ajustada para `decimal_digits=2`.

## [1.11.0] - 2026-06-09

### Adicionado
Expand Down
13 changes: 13 additions & 0 deletions docs/source/referencia/decomp/arquivos/mlt.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.. _mlt:

=============================================
MLT (mlt.dat)
=============================================

.. currentmodule:: idecomp.decomp.mlt

As médias mensais de longo termo (MLT) por posto do DECOMP, localizadas no arquivo geralmente denominado
mlt.dat, são armazenadas na classe:

.. autoclass:: Mlt
:members:
2 changes: 2 additions & 0 deletions docs/source/referencia/decomp/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ DECOMP
idecomp.decomp.hidr.Hidr
idecomp.decomp.inviabunic.InviabUnic
idecomp.decomp.mapcut.Mapcut
idecomp.decomp.mlt.Mlt
idecomp.decomp.oper_desvio_fpha.OperDesvioFpha
idecomp.decomp.oper_disp_usih.OperDispUsih
idecomp.decomp.oper_disp_usih_ree.OperDispUsihRee
Expand Down Expand Up @@ -84,6 +85,7 @@ DECOMP
arquivos/hidr
arquivos/inviabunic
arquivos/mapcut
arquivos/mlt
arquivos/oper_desvio_fpha
arquivos/oper_disp_usih
arquivos/oper_disp_usih_ree
Expand Down
15 changes: 15 additions & 0 deletions docs/source/referencia/libs/arquivos/renovaveis.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.. _renovaveis:

=======================================================
Dados das Usinas Renováveis
=======================================================

.. currentmodule:: idecomp.libs.renovaveis

As informações de usinas renováveis (parques eólicos
equivalentes) no DECOMP, localizadas no arquivos das LIBS
que são indicados no indices.csv com as respectivas
funcionalidades, são armazenados na classe:

.. autoclass:: Renovaveis
:members:
2 changes: 2 additions & 0 deletions docs/source/referencia/libs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ LIBS
.. autosummary::
:nosignatures:

idecomp.libs.renovaveis.Renovaveis
idecomp.libs.restricoes.Restricoes
idecomp.libs.usinas_hidreletricas.UsinasHidreletricas

.. toctree::
:maxdepth: 2

arquivos/renovaveis
arquivos/restricoes
arquivos/usinas_hidreletricas
2 changes: 1 addition & 1 deletion idecomp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
e saída do DECOMP.
"""

__version__ = "1.11.0"
__version__ = "1.12.0"

from . import decomp # noqa
1 change: 1 addition & 0 deletions idecomp/decomp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from .hidr import Hidr # noqa
from .inviabunic import InviabUnic # noqa
from .mapcut import Mapcut # noqa
from .mlt import Mlt # noqa
from .oper_desvio_fpha import OperDesvioFpha # noqa
from .oper_disp_usih_ree import OperDispUsihRee # noqa
from .oper_disp_usih_subm import OperDispUsihSubm # noqa
Expand Down
2 changes: 1 addition & 1 deletion idecomp/decomp/dadger.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ def ue(
:rtype: :class:`UE` | list[:class:`UE`] | :class:`pandas.DataFrame` | None
"""
return self.__registros_ou_df(
UH,
UE,
codigo_usina=codigo_usina,
codigo_submercado=codigo_submercado,
nome_usina=nome_usina,
Expand Down
75 changes: 75 additions & 0 deletions idecomp/decomp/mlt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
from typing import IO, Any, TypeVar

import numpy as np
import pandas as pd # type: ignore[import-untyped]
from cfinterface.files.sectionfile import SectionFile

from idecomp.decomp.modelos.mlt import SecaoMlt


class Mlt(SectionFile):
"""
Armazena os dados de entrada do DECOMP referentes às médias
mensais de longo termo (MLT) de cada posto.
"""

T = TypeVar("T")

SECTIONS = [SecaoMlt]
STORAGE = "BINARY"

def __init__(self, data: Any = ...) -> None:
super().__init__(data)
self.__df: pd.DataFrame | None = None

def write(self, to: str | IO[Any], *args: Any, **kwargs: Any) -> None:
self.__atualiza_secao()
super().write(to, *args, **kwargs)

def __obtem_secao_mlt(self) -> SecaoMlt | None:
s = self.data.get_sections_of_type(SecaoMlt)
return s if not isinstance(s, list) else None

def __atualiza_secao(self) -> None:
dados = self.__obtem_secao_mlt()
if dados is not None and self.__df is not None:
cols_postos = [str(p) for p in range(1, SecaoMlt.NUMERO_POSTOS + 1)]
dados.data = self.__df[cols_postos].to_numpy().flatten().tolist()

@property
def valores(self) -> pd.DataFrame | None:
"""
Obtém a tabela com as médias mensais de longo termo (MLT) de
cada posto, por mês do ano.

- mes (`int`)
- 1 (`int`)
- ...
- N (`int`) : número de postos

:return: A tabela com as médias por mês e posto
:rtype: pd.DataFrame | None
"""
if self.__df is None:
dados = self.__obtem_secao_mlt()
if dados is not None:
cols_postos = [
str(p) for p in range(1, SecaoMlt.NUMERO_POSTOS + 1)
]
df = pd.DataFrame(
np.array(dados.data).reshape(
(SecaoMlt.NUMERO_MESES, SecaoMlt.NUMERO_POSTOS)
),
columns=cols_postos,
)
df["mes"] = list(range(1, SecaoMlt.NUMERO_MESES + 1))
self.__df = df[["mes"] + cols_postos]
return self.__df

@valores.setter
def valores(self, df: pd.DataFrame) -> None:
dados = self.__obtem_secao_mlt()
if dados is not None:
cols_postos = [str(p) for p in range(1, SecaoMlt.NUMERO_POSTOS + 1)]
dados.data = df[cols_postos].to_numpy().flatten().tolist()
self.__df = None
63 changes: 53 additions & 10 deletions idecomp/decomp/modelos/dadger.py
Original file line number Diff line number Diff line change
Expand Up @@ -1051,19 +1051,34 @@ class IA(Register):
LiteralField(2, 9),
LiteralField(2, 14),
IntegerField(1, 17),
FloatField(10, 19, 0),
FloatField(10, 29, 0),
FloatField(10, 39, 0),
FloatField(10, 49, 0),
FloatField(10, 59, 0),
FloatField(10, 69, 0),
FloatField(10, 79, 0),
FloatField(10, 89, 0),
FloatField(10, 99, 0),
FloatField(10, 109, 0),
FloatField(10, 19, 2),
FloatField(10, 29, 2),
FloatField(10, 39, 2),
FloatField(10, 49, 2),
FloatField(10, 59, 2),
FloatField(10, 69, 2),
FloatField(10, 79, 2),
FloatField(10, 89, 2),
FloatField(10, 99, 2),
FloatField(10, 109, 2),
]
)

def __atualiza_dados_lista(
self,
novos_dados: list[Any],
indice_inicial: int,
espacamento: int,
) -> None:
atuais = len(self.data)
ultimo_indice = indice_inicial + espacamento * len(novos_dados)
diferenca = (ultimo_indice - atuais) // espacamento
if diferenca > 0:
self.data += [None] * (ultimo_indice - atuais)
diferenca -= 1
novos_dados += [None] * abs(diferenca)
self.data[indice_inicial::espacamento] = novos_dados

@property
def estagio(self) -> int | None:
"""
Expand Down Expand Up @@ -1106,6 +1121,34 @@ def nome_submercado_para(self) -> str | None:
def nome_submercado_para(self, t: str) -> None:
self.data[2] = t

@property
def limite_de_para(self) -> list[float] | None:
"""
Os limites de intercâmbio no sentido de -> para, por patamar.

:return: Os limites por patamar.
:rtype: list[float] | None
"""
return self.data[4::2]

@limite_de_para.setter
def limite_de_para(self, lim: list[float]) -> None:
self.__atualiza_dados_lista(lim, 4, 2)

@property
def limite_para_de(self) -> list[float] | None:
"""
Os limites de intercâmbio no sentido para -> de, por patamar.

:return: Os limites por patamar.
:rtype: list[float] | None
"""
return self.data[5::2]

@limite_para_de.setter
def limite_para_de(self, lim: list[float]) -> None:
self.__atualiza_dados_lista(lim, 5, 2)


class TX(Register):
"""
Expand Down
42 changes: 42 additions & 0 deletions idecomp/decomp/modelos/mlt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from typing import IO, Any

import numpy as np
from cfinterface.components.section import Section


class SecaoMlt(Section):
"""
Registro com os dados das médias mensais de longo termo (MLT)
de cada posto, por mês do ano.
"""

__slots__: list[str] = []

NUMERO_MESES = 12
NUMERO_POSTOS = 320

def __init__(
self,
previous: Any = None,
next: Any = None,
data: Any = None,
) -> None:
super().__init__(previous, next, data)
self.data = []

def __eq__(self, o: object) -> bool:
if not isinstance(o, SecaoMlt):
return False
bloco: SecaoMlt = o
return self.data == bloco.data

def read(self, file: IO[Any], *args: Any, **kwargs: Any) -> None: # type: ignore[override]
dados = np.frombuffer(
file.read(SecaoMlt.NUMERO_MESES * SecaoMlt.NUMERO_POSTOS * 4),
dtype=np.int32,
count=SecaoMlt.NUMERO_MESES * SecaoMlt.NUMERO_POSTOS,
)
self.data = list(dados)

def write(self, file: IO[Any], *args: Any, **kwargs: Any) -> None: # type: ignore[override]
file.write(np.array(self.data, dtype=np.int32).tobytes())
1 change: 1 addition & 0 deletions idecomp/libs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Inclui os membros

from .renovaveis import Renovaveis # noqa
from .usinas_hidreletricas import UsinasHidreletricas # noqa
Loading
Loading