Nota
Go to the end to download the full example code.
Análise de patamares de carga e curva de demanda
O arquivo patamar.dat define os patamares de carga utilizados no modelo NEWAVE para representar a variação horária da demanda. Este arquivo é fundamental para a modelagem da operação energética, pois define como a carga varia ao longo do dia e entre diferentes períodos do ano.
import plotly.express as px
import plotly.io as pio
from inewave.newave import Patamar
pio.templates.default = "ggplot2"
# Leitura do arquivo patamar.dat
arq_patamar = Patamar.read("./newave/patamar.dat")
Configuração básica dos patamares
Verificando o número de patamares definidos:
num_patamares = arq_patamar.numero_patamares
Análise da duração dos patamares
A duração define quantas horas por mês cada patamar representa:
duracao = arq_patamar.duracao_mensal_patamares
print(f"Total de registros de duração: {len(duracao)}")
print(f"Patamares na duração: {sorted(duracao['patamar'].unique())}")
print(f"Período: {duracao['data'].min()} a {duracao['data'].max()}")
print("\nPrimeiros registros de duração:")
print(duracao.head())
# Análise estatística das durações
print("\nEstatísticas das durações por patamar:")
duracao_stats = duracao.groupby("patamar")["valor"].agg([
"mean",
"std",
"min",
"max",
])
print(duracao_stats.round(2))
# Verificação da soma das durações (deve ser próximo a 744 horas/mês em média)
duracao_mensal_total = duracao.groupby("data")["valor"].sum()
print(
f"\nDuração total mensal (média): {duracao_mensal_total.mean():.1f} horas"
)
print(
f"Variação: {duracao_mensal_total.min():.1f} - {duracao_mensal_total.max():.1f} horas"
)
# Visualização da duração ao longo do tempo
if len(duracao["patamar"].unique()) > 1:
fig = px.line(
duracao,
x="data",
y="valor",
color="patamar",
title="Evolução da Duração dos Patamares ao Longo do Tempo",
labels={
"data": "Data",
"valor": "Duração (horas)",
"patamar": "Patamar",
},
)
fig
Total de registros de duração: 180
Patamares na duração: [np.int64(1), np.int64(2), np.int64(3)]
Período: 2025-01-01 00:00:00 a 2029-12-01 00:00:00
Primeiros registros de duração:
data patamar valor
0 2025-01-01 1 0.2366
1 2025-02-01 1 0.2381
2 2025-03-01 1 0.2151
3 2025-04-01 1 0.1944
4 2025-05-01 1 0.1411
Estatísticas das durações por patamar:
mean std min max
patamar
1 0.19 0.04 0.13 0.25
2 0.37 0.02 0.34 0.39
3 0.44 0.03 0.40 0.50
Duração total mensal (média): 1.0 horas
Variação: 1.0 - 1.0 horas
Análise das cargas por patamar
As cargas em P.U. mostram como a demanda varia entre patamares:
carga = arq_patamar.carga_patamares
print(f"Total de registros de carga: {len(carga)}")
print(f"Submercados: {sorted(carga['codigo_submercado'].unique())}")
print(f"Patamares: {sorted(carga['patamar'].unique())}")
print("\nPrimeiros registros de carga:")
print(carga.head())
# Análise das cargas médias por patamar
print("\nCarga média por patamar (P.U.):")
carga_media_patamar = carga.groupby("patamar")["valor"].agg(["mean", "std"])
print(carga_media_patamar.round(4))
# Análise sazonal das cargas
if "data" in carga.columns:
carga_copy = carga.copy()
carga_copy["mes"] = carga_copy["data"].dt.month
print("\nVariação sazonal das cargas por patamar:")
carga_sazonal = (
carga_copy.groupby(["mes", "patamar"])["valor"].mean().reset_index()
)
# Visualização sazonal
if len(carga["patamar"].unique()) > 1:
fig = px.line(
carga_sazonal,
x="mes",
y="valor",
color="patamar",
title="Variação Sazonal das Cargas por Patamar",
labels={
"mes": "Mês",
"valor": "Carga (P.U.)",
"patamar": "Patamar",
},
)
fig.update_xaxes(tickmode="linear", dtick=1)
fig
# Análise por submercado
if len(carga["codigo_submercado"].unique()) > 1:
print("\nCarga média por submercado e patamar:")
carga_subm_pat = (
carga.groupby(["codigo_submercado", "patamar"])["valor"]
.mean()
.reset_index()
)
carga_pivot = carga_subm_pat.pivot(
index="codigo_submercado", columns="patamar", values="valor"
)
print(carga_pivot.round(4))
Total de registros de carga: 720
Submercados: [np.int64(1), np.int64(2), np.int64(3), np.int64(4)]
Patamares: [np.int64(1), np.int64(2), np.int64(3)]
Primeiros registros de carga:
codigo_submercado data patamar valor
0 1 2025-01-01 1 1.0941
1 1 2025-02-01 1 1.0855
2 1 2025-03-01 1 1.0912
3 1 2025-04-01 1 1.1116
4 1 2025-05-01 1 1.1085
Carga média por patamar (P.U.):
mean std
patamar
1 1.0803 0.0571
2 1.0798 0.0292
3 0.8985 0.0427
Variação sazonal das cargas por patamar:
Carga média por submercado e patamar:
patamar 1 2 3
codigo_submercado
1 1.1121 1.0857 0.8801
2 1.1532 1.1125 0.8406
3 1.0299 1.0754 0.9235
4 1.0259 1.0454 0.9497
Análise da modulação da carga
Verificando como a carga se distribui entre os patamares:
print("Análise da modulação da carga:")
# Merge entre carga e duração para calcular energia por patamar
carga_duracao = carga.merge(
duracao, on=["data", "patamar"], suffixes=("_carga", "_duracao")
)
# Calculando energia por patamar (carga * duração)
carga_duracao["energia_patamar"] = (
carga_duracao["valor_carga"] * carga_duracao["valor_duracao"]
)
# Energia total por submercado e mês
energia_total = carga_duracao.groupby(["codigo_submercado", "data"])[
"energia_patamar"
].sum()
# Participação de cada patamar na energia total
carga_duracao_energia = carga_duracao.merge(
energia_total.reset_index().rename(
columns={"energia_patamar": "energia_total"}
),
on=["codigo_submercado", "data"],
)
carga_duracao_energia["participacao_pct"] = (
carga_duracao_energia["energia_patamar"]
/ carga_duracao_energia["energia_total"]
* 100
)
print("Participação média de cada patamar na energia total:")
participacao_media = carga_duracao_energia.groupby("patamar")[
"participacao_pct"
].mean()
for patamar, part in participacao_media.items():
print(f"Patamar {patamar}: {part:.1f}%")
# Visualização da modulação
if len(carga_duracao_energia["patamar"].unique()) > 1:
fig = px.box(
carga_duracao_energia,
x="patamar",
y="participacao_pct",
title="Distribuição da Participação dos Patamares na Energia Total",
labels={
"patamar": "Patamar",
"participacao_pct": "Participação (%)",
},
)
fig
Análise da modulação da carga:
Participação média de cada patamar na energia total:
Patamar 1: 20.8%
Patamar 2: 39.6%
Patamar 3: 39.6%
Análise do intercâmbio por patamares
Fatores de correção do intercâmbio entre submercados:
intercambio = arq_patamar.intercambio_patamares
print(f"Registros de intercâmbio por patamares: {len(intercambio)}")
print("Pares de submercados com intercâmbio:")
pares_intercambio = intercambio.groupby([
"submercado_de",
"submercado_para",
]).size()
print(pares_intercambio)
# Análise dos fatores de intercâmbio
print("\nEstatísticas dos fatores de intercâmbio:")
intercambio_stats = intercambio.groupby("patamar")["valor"].agg([
"mean",
"std",
"min",
"max",
])
print(intercambio_stats.round(4))
# Verificando se há assimetrias significativas
if len(intercambio) > 0:
fatores_extremos = intercambio[
(intercambio["valor"] < 0.8) | (intercambio["valor"] > 1.2)
]
if len(fatores_extremos) > 0:
print(
f"\nFatores de intercâmbio extremos (fora da faixa 0.8-1.2): {len(fatores_extremos)}"
)
print("Casos extremos:")
print(
fatores_extremos[
["submercado_de", "submercado_para", "patamar", "valor"]
].head()
)
else:
print(
"\n✓ Todos os fatores de intercâmbio estão na faixa razoável (0.8-1.2)"
)
Registros de intercâmbio por patamares: 2160
Pares de submercados com intercâmbio:
submercado_de submercado_para
1 2 180
3 180
4 180
11 180
2 1 180
3 1 180
11 180
4 1 180
11 180
11 1 180
3 180
4 180
dtype: int64
Estatísticas dos fatores de intercâmbio:
mean std min max
patamar
1 1.0062 0.0711 0.6666 1.9346
2 0.9697 0.0711 0.6887 1.3476
3 1.0225 0.0584 0.5775 1.3265
Fatores de intercâmbio extremos (fora da faixa 0.8-1.2): 69
Casos extremos:
submercado_de submercado_para patamar valor
17 1 2 2 0.6960
18 1 2 2 0.6997
19 1 2 2 0.7299
20 1 2 2 0.7359
21 1 2 2 0.7364
Análise das usinas não simuladas
Fatores para representar geração não simulada individualmente:
usinas_nao_sim = arq_patamar.usinas_nao_simuladas
print(f"Registros de usinas não simuladas: {len(usinas_nao_sim)}")
print(f"Submercados: {sorted(usinas_nao_sim['codigo_submercado'].unique())}")
print(f"Blocos de usinas: {sorted(usinas_nao_sim['indice_bloco'].unique())}")
# Análise dos fatores por patamar
print("\nFatores médios das usinas não simuladas por patamar:")
uns_por_patamar = usinas_nao_sim.groupby("patamar")["valor"].agg([
"mean",
"std",
"count",
])
print(uns_por_patamar.round(4))
# Análise por submercado
print("\nFatores médios por submercado:")
uns_por_subm = usinas_nao_sim.groupby("codigo_submercado")["valor"].agg([
"mean",
"std",
])
print(uns_por_subm.round(4))
# Variabilidade temporal
if "data" in usinas_nao_sim.columns:
uns_temporal = usinas_nao_sim.groupby("data")["valor"].mean()
print("\nVariabilidade temporal:")
print(f"Fator médio mínimo: {uns_temporal.min():.4f}")
print(f"Fator médio máximo: {uns_temporal.max():.4f}")
print(
f"Coeficiente de variação: {uns_temporal.std() / uns_temporal.mean():.4f}"
)
Registros de usinas não simuladas: 5760
Submercados: [np.int64(1), np.int64(2), np.int64(3), np.int64(4)]
Blocos de usinas: [np.int64(1), np.int64(2), np.int64(3), np.int64(4), np.int64(5), np.int64(6), np.int64(7), np.int64(8)]
Fatores médios das usinas não simuladas por patamar:
mean std count
patamar
1 0.8615 0.3209 1920
2 1.1313 0.2505 1920
3 0.9471 0.1027 1920
Fatores médios por submercado:
mean std
codigo_submercado
1 0.9874 0.2828
2 0.9792 0.2556
3 0.9741 0.2701
4 0.9793 0.2595
Variabilidade temporal:
Fator médio mínimo: 0.9592
Fator médio máximo: 1.0000
Coeficiente de variação: 0.0141
Criação de cenários alternativos
Modificando patamares para estudos específicos:
print("Exemplo de modificação de patamares:")
# Cenário: Aumentando a modulação da carga (diferença entre ponta e fora ponta)
carga_modificada = carga.copy()
if len(carga["patamar"].unique()) >= 2:
# Identificando patamar de ponta (maior carga média) e fora ponta (menor carga média)
carga_media = carga.groupby("patamar")["valor"].mean()
patamar_ponta = carga_media.idxmax()
patamar_leve = carga_media.idxmin()
print(
f"Patamar de ponta identificado: {patamar_ponta} (carga média: {carga_media[patamar_ponta]:.3f})"
)
print(
f"Patamar leve identificado: {patamar_leve} (carga média: {carga_media[patamar_leve]:.3f})"
)
# Aplicando modificação: +10% na ponta, -5% no leve
mask_ponta = carga_modificada["patamar"] == patamar_ponta
mask_leve = carga_modificada["patamar"] == patamar_leve
carga_modificada.loc[mask_ponta, "valor"] *= 1.10
carga_modificada.loc[mask_leve, "valor"] *= 0.95
# Comparação
nova_media_ponta = carga_modificada[mask_ponta]["valor"].mean()
nova_media_leve = carga_modificada[mask_leve]["valor"].mean()
print(
f"Nova carga ponta: {nova_media_ponta:.3f} (+{(nova_media_ponta / carga_media[patamar_ponta] - 1) * 100:.1f}%)"
)
print(
f"Nova carga leve: {nova_media_leve:.3f} ({(nova_media_leve / carga_media[patamar_leve] - 1) * 100:.1f}%)"
)
# Aplicando modificação ao arquivo
arq_patamar.carga_patamares = carga_modificada
print("✓ Modificação aplicada ao arquivo")
Exemplo de modificação de patamares:
Patamar de ponta identificado: 1 (carga média: 1.080)
Patamar leve identificado: 3 (carga média: 0.898)
Nova carga ponta: 1.188 (+10.0%)
Nova carga leve: 0.854 (-5.0%)
✓ Modificação aplicada ao arquivo
Total running time of the script: (0 minutes 0.129 seconds)