Co-Study4Grid / scripts /generate_baseline.py
github-actions[bot]
Deploy 7688ef1
13d4e44
Raw
History Blame Contribute Delete
5.61 kB
# Copyright (c) 2025-2026, RTE (https://www.rte-france.com)
# This Source Code Form is subject to the terms of the Mozilla Public License, version 2.0.
# If a copy of the Mozilla Public License, version 2.0 was not distributed with this file,
# you can obtain one at http://mozilla.org/MPL/2.0/.
# SPDX-License-Identifier: MPL-2.0
# This file is part of Co-Study4Grid a Power Grid Study tool Assistant Interface to help solve contigencies for a grid state under study.
import sys
import os
import json
from pathlib import Path
# Add project root to sys.path
sys.path.insert(0, "/home/marotant/dev/AntiGravity/ExpertAssist")
from expert_backend.services.recommender_service import recommender_service
from expert_op4grid_recommender import config
def generate_baseline():
network_path = "/home/marotant/dev/AntiGravity/ExpertAssist/data/bare_env_small_grid_test"
action_file_path = "/home/marotant/dev/AntiGravity/ExpertAssist/data/action_space/reduced_model_actions_test.json"
disconnected_element = "P.SAOL31RONCI"
# Mapping of action IDs to their relevant voltage level
action_vl_map = {
"node_merging_PYMONP3": "PYMONP3",
"f344b395-9908-43c2-bca0-75c5f298465e_COUCHP6": "COUCHP6"
}
print("Setting up config...")
class Settings:
def __init__(self, network_path, action_file_path):
self.network_path = network_path
self.action_file_path = action_file_path
self.min_line_reconnections = 1
self.min_close_coupling = 1
self.min_open_coupling = 1
self.min_line_disconnections = 1
self.n_prioritized_actions = 20
self.monitoring_factor = 0.95
self.pre_existing_overload_threshold = 0.02
self.lines_monitoring_path = None
recommender_service.update_config(Settings(network_path, action_file_path))
# Import and load network service
from expert_backend.services.network_service import network_service
network_service.load_network(str(network_path))
print(f"Running analysis for {disconnected_element}...")
# Capture the output of run_analysis which contains the recommendations
iterator = recommender_service.run_analysis(disconnected_element)
for _ in iterator: pass # consume it
result = recommender_service._last_result
prioritized = result.get("prioritized_actions", {})
# KEY FIX: Use the observation of the contingency from the analysis results
# recommender_service.run_analysis doesn't explicitly store obs_contingency in _last_result
# but the Backend.run_analysis does! Let's check internal state.
# Actually, we can just get it from any recommended action's 'n1_obs' if available,
# or re-simulate if we must. But wait, get_action_variant_diagram re-simulates it!
# To be 100% consistent with the diagram labels, we MUST use the logic in
# get_action_variant_diagram (lines 485-496 approx).
print("Simulating N-1 state...")
n1_network = recommender_service._load_network()
if disconnected_element:
try:
n1_network.disconnect(disconnected_element)
except Exception:
pass
from expert_op4grid_recommender.utils.make_env_utils import create_olf_rte_parameter
import pypowsybl as pp
params = create_olf_rte_parameter()
pp.loadflow.run_ac(n1_network, params)
n1_flows = recommender_service._get_network_flows(n1_network)
baseline = {
"contingency": disconnected_element,
"actions": {}
}
for aid, target_vl in action_vl_map.items():
if aid not in prioritized:
print(f"Warning: Action {aid} not found in analysis results.")
continue
print(f"Capturing baseline for {aid} (Target VL: {target_vl})...")
obs_after = prioritized[aid]["observation"]
# Switch to the correct variant
variant_id = obs_after._variant_id
nm = obs_after._network_manager
nm.set_working_variant(variant_id)
n_after = nm.network
after_flows = recommender_service._get_network_flows(n_after)
# Get target branches
lines = n_after.get_lines()
target_lines = lines[(lines.voltage_level1_id == target_vl) | (lines.voltage_level2_id == target_vl)].index.tolist()
trafos = n_after.get_2_windings_transformers()
target_trafos = trafos[(trafos.voltage_level1_id == target_vl) | (trafos.voltage_level2_id == target_vl)].index.tolist()
target_branch_ids = set(target_lines + target_trafos)
# Compute deltas matching diagram logic
deltas = recommender_service._compute_deltas(after_flows, n1_flows, voltage_level_ids=[target_vl])
filtered_p = {bid: data for bid, data in deltas["flow_deltas"].items() if bid in target_branch_ids}
filtered_q = {bid: data for bid, data in deltas["reactive_flow_deltas"].items() if bid in target_branch_ids}
print(f" Results for {aid}:")
for bid, d in filtered_p.items():
print(f" {bid}: P={d['delta']}, Q={filtered_q[bid]['delta']}")
baseline["actions"][aid] = {
"target_voltage_level": target_vl,
"flow_deltas": filtered_p,
"reactive_flow_deltas": filtered_q
}
output_path = Path("tests/baseline_scenario.json")
with open(output_path, "w") as f:
json.dump(baseline, f, indent=2)
print(f"Baseline saved to {output_path}")
if __name__ == "__main__":
generate_baseline()