Arquitetura Interna

Esta página descreve a organização interna do sintetizador-decomp, cobrindo as camadas que compõem a aplicação, o fluxo de dados desde a leitura dos arquivos do DECOMP até a exportação das sínteses, e o papel de cada pacote principal.

Visao Geral

O sintetizador-decomp é estruturado em seis pacotes principais dentro do diretório app/. A organização segue uma arquitetura em camadas: a interface de linha de comando recebe os comandos do usuário, os despacha para a camada de serviços, que coordena a leitura dos arquivos de entrada (deck do DECOMP) e a produção dos DataFrames de saída, que por sua vez são exportados pelo repositório de persistência.

Cada camada tem uma responsabilidade claramente delimitada e depende apenas das camadas abaixo dela, o que facilita o teste unitário e a substituição de implementações concretas por alternativas (por exemplo, diferentes formatos de exportação ou diferentes fontes de arquivos).

O diagrama a seguir ilustra a dependência entre os pacotes:

┌──────────────────────────────────────────────────────────┐
│                   app/app.py  (CLI - click)              │
└────────────────────────┬─────────────────────────────────┘
                         │ despacha Commands
                         ▼
┌──────────────────────────────────────────────────────────┐
│          app/services/handlers.py  (Handlers)            │
└──────────┬───────────────────────────────────┬───────────┘
           │ instancia Synthetizers             │ usa UnitOfWork
           ▼                                   ▼
┌─────────────────────┐           ┌─────────────────────────┐
│  app/services/      │           │  app/services/          │
│  synthesis/         │◄──────────│  unitofwork.py          │
│  (Synthetizers)     │  usa Deck │                         │
└──────────┬──────────┘           └──────────┬──────────────┘
           │ lê dados do Deck                 │ provê repositórios
           ▼                                  ▼
┌─────────────────────┐           ┌─────────────────────────┐
│  app/services/      │           │  app/adapters/          │
│  deck/              │           │  repository/            │
│  (Deck + módulos)   │           │  (Files + Export)       │
└──────────┬──────────┘           └──────────┬──────────────┘
           │ via idecomp                      │ lê/escreve
           ▼                                  ▼
┌─────────────────────┐           ┌─────────────────────────┐
│  Arquivos do DECOMP │           │  Arquivos de saída      │
│  (dadger.rv0,       │           │  sintese/*.parquet      │
│   relato, dec_oper, │           │  sintese/*.csv          │
│   hidr.dat, etc.)   │           │                         │
└─────────────────────┘           └─────────────────────────┘

Dependências transversais (usadas em todas as camadas):
  app/model/      – enumerações e dataclasses do modelo de dados
  app/internal/   – constantes e nomes de colunas compartilhados
  app/utils/      – logging, temporização, encoding, singleton, etc.

Fluxo de Dados

O fluxo completo de uma execução de síntese percorre as seguintes etapas:

Usuário
  │
  │  $ sintetizador-decomp operacao CMO_SBM EVER_SBM
  │
  ▼
CLI (app/app.py)
  │  Cria: commands.SynthetizeOperation(["CMO_SBM", "EVER_SBM"])
  │  Cria: FSUnitOfWork (diretório de trabalho atual)
  │
  ▼
Handler (app/services/handlers.py)
  │  Chama: OperationSynthetizer.synthetize(variables, uow)
  │
  ▼
Synthetizer (app/services/synthesis/operation/orchestrator.py)
  │  Resolve mnemônicos → OperationSynthesis (variável + agregação espacial)
  │  Para cada síntese:
  │
  ├──► Deck (app/services/deck/deck.py)
  │      │  Lê e armazena em cache os arquivos do deck do DECOMP
  │      │  (dadger.rv0, hidr.dat, relato, dec_oper_usih, ...)
  │      │  via AbstractFilesRepository (app/adapters/repository/files.py)
  │      │  que usa a biblioteca `idecomp` para parsing
  │      └─► Retorna DataFrames Polars com dados do sistema
  │
  ├──► Processa os dados brutos:
  │      – Filtra, agrega e calcula limites operativos
  │      – Aplica unidades e resolução espacial
  │      – Monta o DataFrame final normalizado
  │
  └──► AbstractExportRepository (app/adapters/repository/export.py)
         │  Recebe o DataFrame Polars ou pandas
         │  Escreve em disco no formato configurado:
         │    PARQUET → sintese/CMO_SBM.parquet
         │    CSV     → sintese/CMO_SBM.csv
         └─► Arquivo de saída gravado

Modulos Principais

Esta seção descreve o papel de cada pacote do diretório app/.

app/domain

Contém os comandos da aplicação, implementados como dataclasses simples. Os comandos carregam apenas os dados de entrada fornecidos pelo usuário (lista de mnemônicos de variáveis) e não possuem lógica de negócio. Seguem o padrão Command do Domain-Driven Design.

Arquivos do pacote domain

Arquivo

Papel

commands.py

Define SynthetizeSystem, SynthetizeExecution, SynthetizeScenarios, SynthetizeOperation e SynthetizePolicy como dataclasses com o campo variables: list[str].

app/model

Define o modelo unificado de dados: enumerações de variáveis, agregações espaciais e dataclasses de síntese para cada categoria. Este pacote não realiza I/O nem processamento; é a linguagem compartilhada entre as camadas de serviço e de domínio.

Subpacotes do pacote model

Subpacote

Papel

model/operation/

Enumerações de variáveis da operação (Variable), agregação espacial (SpatialResolution) e unidade (Unit); dataclass OperationSynthesis.

model/scenarios/

Enumerações de variáveis de cenários; dataclass ScenarioSynthesis.

model/execution/

Enumeração de variáveis de execução e infeasibilidades; dataclass ExecutionSynthesis.

model/policy/

Enumeração de variáveis da política; dataclass PolicySynthesis.

model/system/

Enumeração de variáveis do sistema; dataclass SystemSynthesis.

model/settings.py

Classe Settings (singleton) que lê variáveis de ambiente como FORMATO_SINTESE, PROCESSADORES e DIRETORIO_SINTESE.

app/services

Contém toda a lógica de orquestração e processamento: os handlers que recebem comandos e os despacham, os sintetizadores que implementam o pipeline de síntese para cada categoria, o Deck que fornece acesso cacheado aos dados de entrada, e o Unit of Work que gerencia o ciclo de vida dos repositórios.

Arquivos e subpacotes do pacote services

Arquivo / Subpacote

Papel

handlers.py

Funções de despacho de alto nível. Cada função recebe um Command e um AbstractUnitOfWork, instancia o sintetizador correspondente e delega a execução.

unitofwork.py

Define AbstractUnitOfWork e a implementação concreta FSUnitOfWork. Gerencia o ciclo de vida dos repositórios de arquivos e de exportação, criando o diretório de saída (sintese/) quando necessário.

synthesis/system.py

SystemSynthetizer: sintetiza dados estáticos do sistema (submercados, usinas, patamares de carga, estágios do estudo).

synthesis/execution.py

ExecutionSynthetizer: sintetiza metadados da execução (versão do modelo, tempo de processamento, infeasibilidades).

synthesis/scenarios.py

ScenariosSynthetizer: sintetiza cenários de afluências e vazões naturais a partir dos arquivos de saída do DECOMP.

synthesis/operation/orchestrator.py

OperationSynthetizer: ponto de entrada do pipeline de síntese de operação. Resolve mnemônicos, coordena o cache e despacha para os módulos de processamento.

synthesis/operation/cache.py

Gerenciamento de cache dos DataFrames intermediários de operação, evitando recálculo de sínteses já processadas dentro de uma mesma execução.

synthesis/operation/export.py

Funções de exportação do resultado final de cada síntese de operação para o repositório de exportação configurado.

synthesis/operation/pipeline.py

Funções do pipeline de transformação dos dados brutos de operação: filtragem, agregação e normalização.

synthesis/operation/spatial.py

Funções de resolução e agregação espacial das variáveis de operação (por submercado, REE, usina, bacia, sistema interligado).

synthesis/operation/stubs.py

Stubs de sínteses não disponíveis ou com processamento especial, usados para preencher sínteses faltantes com DataFrames vazios tipados.

deck/deck.py

Classe Deck com métodos de classe cacheados para acesso aos dados de entrada do DECOMP. Cada método acessa um arquivo de deck específico através do repositório de arquivos e retorna DataFrames Polars prontos para uso.

deck/accessors.py

Funções auxiliares de acesso e cache dos objetos de arquivo do DECOMP via a biblioteca idecomp.

deck/entities.py

Constrói DataFrames de entidades do sistema (usinas hidroelétricas, termoelétricas, submercados, patamares).

deck/context.py

Funções de construção do contexto de execução (número de revisões, estágios e períodos do estudo).

deck/processing.py

Funções de processamento dos dados brutos lidos dos arquivos do deck, incluindo conversões de unidades e normalização de séries temporais.

deck/operations.py

Funções de leitura e interpretação dos resultados de operação a partir dos arquivos dec_oper_* do DECOMP.

deck/reports.py

Funções de leitura dos arquivos de relatório do DECOMP (relato, relato2) para extração de metadados de execução.

deck/bounds.py

Funções de cálculo dos limites operativos (mínimos e máximos) das variáveis de operação, implementadas com DataFrames Polars.

app/adapters

Implementa o padrão Repository: abstrai o acesso aos arquivos de entrada do DECOMP e a gravação dos arquivos de saída sintetizados, permitindo que a camada de serviços não dependa de detalhes de I/O ou de formatos específicos.

Arquivos do pacote adapters

Arquivo

Papel

repository/files.py

Define AbstractFilesRepository e a implementação concreta RawFilesRepository, que utiliza a biblioteca idecomp para fazer o parsing dos arquivos de entrada do DECOMP (dadger.rv0, hidr.dat, arquivos dec_oper_*, relato, etc.). Os objetos de arquivo são mantidos em cache para evitar releituras.

repository/export.py

Define AbstractExportRepository e as implementações concretas ParquetExportRepository (escreve via PyArrow), CSVExportRepository (escreve via pandas) e TestExportRepository (no-op para testes). A implementação concreta é selecionada pela variável de ambiente FORMATO_SINTESE.

app/utils

Fornece utilitários transversais utilizados em todas as camadas da aplicação.

Arquivos do pacote utils

Arquivo

Papel

log.py

Classe Log (singleton) que configura o logging assíncrono baseado em multiprocessing.Queue, permitindo que processos filhos (usados no paralelismo de síntese) enviem registros de log ao processo principal.

timing.py

Decorador e função auxiliar time_and_log para medir e registrar o tempo de execução de cada etapa da síntese.

singleton.py

Metaclasse Singleton utilizada por Log e Settings para garantir instância única durante toda a execução.

encoding.py

Função assíncrona de conversão de codificação para normalizar arquivos de entrada antes da leitura pelo idecomp.

regex.py

Função match_variables_with_wildcards para resolver mnemônicos fornecidos pelo usuário (que podem conter curingas) em listas de variáveis suportadas.

terminal.py

Utilitários para formatação de saída no terminal.

fs.py

Funções auxiliares de sistema de arquivos.

operations.py

Funções de operações numéricas auxiliares.

tz.py

Função enforce_utc que garante que colunas de datetime nos DataFrames exportados estejam na timezone UTC, assegurando compatibilidade na leitura posterior.

app/internal

Centraliza as constantes compartilhadas por todas as camadas da aplicação, evitando strings mágicas espalhadas pelo código.

Arquivos do pacote internal

Arquivo

Papel

constants.py

Define nomes de colunas dos DataFrames (e.g., STAGE_COL, SCENARIO_COL, VALUE_COL), nomes de arquivos de metadados de saída, fatores de conversão de unidades, e listas de colunas comuns a cada categoria de síntese.

Modelo de Dados

O modelo de dados unificado é descrito em detalhe na página Modelo Unificado de Dados. Em resumo, as sínteses são organizadas em cinco categorias:

Categorias de Sintese

Categoria

Descricao

Sistema

Dados estáticos da representação do sistema: submercados, usinas hidroelétricas e termoelétricas, patamares de carga e estágios do estudo.

Execucao

Metadados sobre a execução do modelo: versão, título, tempo de processamento, infeasibilidades e relatório de convergência.

Cenarios

Séries temporais dos cenários de afluências e vazões naturais utilizados pelo DECOMP na otimização.

Operacao

Resultados da operação: custo marginal, energia vertida, geração hidráulica e térmica, vazões, intercâmbios e violações operativas, por estágio, cenário e agregação espacial.

Politica

Dados da política operativa: cortes de Benders calculados e estados visitados na construção dos cortes.

Cada variável sintetizada é identificada por um mnemônico no formato VARIAVEL_AGREGACAO (e.g., CMO_SBM, EVER_SBM, GHID_UHE). O mapeamento completo entre mnemônicos e grandezas físicas está em Modelo Unificado de Dados.